/* ------------------------------------------------------ * |
204 |
205 | process_rq( char *rq, int fd ) |
206 |
207 | 分析客户端的请求,分析然后做出相应的应答 |
208 |
209 | rq is HTTP command: GET /foo/bar.html HTTP/1.0 |
210 |
211 | ------------------------------------------------------ */ |
212 |
213 |
214 |
215 | process_rq( char *rq, int fd ) |
216 |
217 | { |
218 |
219 | char cmd[BUFSIZ], arg[BUFSIZ]; |
220 |
221 |
222 |
223 | /* create a new process and return if not the child */ |
224 |
225 | if ( fork() != 0 ) |
226 |
227 | return ; |
228 |
229 |
230 |
231 | strcpy (arg, "./" ); /* precede args with ./ */ |
232 |
233 | if ( sscanf (rq, "%s%s" , cmd, arg+2) != 2 ) |
234 |
235 | return ; |
236 |
237 |
238 |
239 | if ( strcmp (cmd, "GET" ) != 0 ) |
240 |
241 | cannot_do(fd); |
242 |
243 | else if ( not_exist( arg ) ) |
244 |
245 | do_404(arg, fd ); |
246 |
247 | else if ( isadir( arg ) ) |
248 |
249 | do_ls( arg, fd ); |
250 |
251 | else if ( ends_in_cgi( arg ) ) |
252 |
253 | do_exec( arg, fd ); |
254 |
255 | else |
256 |
257 | do_cat( arg, fd ); |
258 |
259 | } |
260 |
261 |
262 |
263 | /* ------------------------------------------------------ * |
264 |
265 | the reply header thing: all functions need one |
266 |
267 | if content_type is NULL then don't send content type |
268 |
269 | ------------------------------------------------------ */ |
270 |
271 |
272 |
273 | header( FILE *fp, char *content_type ) |
274 |
275 | { |
276 |
277 | fprintf (fp, "HTTP/1.0 200 OK\r\n" ); |
278 |
279 | if ( content_type ) |
280 |
281 | fprintf (fp, "Content-type: %s\r\n" , content_type ); |
282 |
283 | } |
284 |
285 |
286 |
287 | /* ------------------------------------------------------ * |
288 |
289 | simple functions first: |
290 |
291 | cannot_do(fd) unimplemented HTTP command |
292 |
293 | and do_404(item,fd) no such object |
294 |
295 | ------------------------------------------------------ */ |
296 |
297 |
298 |
299 | cannot_do( int fd) |
300 |
301 | { |
302 |
303 | FILE *fp = fdopen(fd, "w" ); |
304 |
305 |
306 |
307 | fprintf (fp, "HTTP/1.0 501 Not Implemented\r\n" ); |
308 |
309 | fprintf (fp, "Content-type: text/plain\r\n" ); |
310 |
311 | fprintf (fp, "\r\n" ); |
312 |
313 |
314 |
315 | fprintf (fp, "That command is not yet implemented\r\n" ); |
316 |
317 | fclose (fp); |
318 |
319 | } |
320 |
321 |
322 |
323 | do_404( char *item, int fd) |
324 |
325 | { |
326 |
327 | FILE *fp = fdopen(fd, "w" ); |
328 |
329 |
330 |
331 | fprintf (fp, "HTTP/1.0 404 Not Found\r\n" ); |
332 |
333 | fprintf (fp, "Content-type: text/plain\r\n" ); |
334 |
335 | fprintf (fp, "\r\n" ); |
336 |
337 |
338 |
339 | fprintf (fp, "The item you requested: %s\r\nis not found\r\n" , |
340 |
341 | item); |
342 |
343 | fclose (fp); |
344 |
345 | } |
346 |
347 |
348 |
349 | /* ------------------------------------------------------ * |
350 |
351 | the directory listing section |
352 |
353 | isadir() uses stat, not_exist() uses stat |
354 |
355 | do_ls runs ls. It should not |
356 |
357 | ------------------------------------------------------ */ |
358 |
359 |
360 |
361 | isadir( char *f) |
362 |
363 | { |
364 |
365 | struct stat info; |
366 |
367 | return ( stat(f, &info) != -1 && S_ISDIR(info.st_mode) ); |
368 |
369 | } |
370 |
371 |
372 |
373 | not_exist( char *f) |
374 |
375 | { |
376 |
377 | struct stat info; |
378 |
379 | return ( stat(f,&info) == -1 ); |
380 |
381 | } |
382 |
383 |
384 |
385 | do_ls( char *dir, int fd) |
386 |
387 | { |
388 |
389 | FILE *fp ; |
390 |
391 |
392 |
393 | fp = fdopen(fd, "w" ); |
394 |
395 | header(fp, "text/plain" ); |
396 |
397 | fprintf (fp, "\r\n" ); |
398 |
399 | fflush (fp); |
400 |
401 |
402 |
403 | dup2(fd,1); |
404 |
405 | dup2(fd,2); |
406 |
407 | close(fd); |
408 |
409 | execlp( "ls" , "ls" , "-l" ,dir,NULL); |
410 |
411 | perror (dir); |
412 |
413 | exit (1); |
414 |
415 | } |
416 |
417 |
418 |
419 | /* ------------------------------------------------------ * |
420 |
421 | the cgi stuff. function to check extension and |
422 |
423 | one to run the program. |
424 |
425 | ------------------------------------------------------ */ |
426 |
427 |
428 |
429 | char * file_type( char *f) |
430 |
431 | /* returns 'extension' of file */ |
432 |
433 | { |
434 |
435 | char *cp; |
436 |
437 | if ( (cp = strrchr (f, '.' )) != NULL ) |
438 |
439 | return cp+1; |
440 |
441 | return "" ; |
442 |
443 | } |
444 |
445 |
446 |
447 | ends_in_cgi( char *f) |
448 |
449 | { |
450 |
451 | return ( strcmp ( file_type(f), "cgi" ) == 0 ); |
452 |
453 | } |
454 |
455 |
456 |
457 | do_exec( char *prog, int fd ) |
458 |
459 | { |
460 |
461 | FILE *fp ; |
462 |
463 |
464 |
465 | fp = fdopen(fd, "w" ); |
466 |
467 | header(fp, NULL); |
468 |
469 | fflush (fp); |
470 |
471 | dup2(fd, 1); |
472 |
473 | dup2(fd, 2); |
474 |
475 | close(fd); |
476 |
477 | execl(prog,prog,NULL); |
478 |
479 | perror (prog); |
480 |
481 | } |
482 |
483 | /* ------------------------------------------------------ * |
484 |
485 | do_cat(filename,fd) |
486 |
487 | sends back contents after a header |
488 |
489 | ------------------------------------------------------ */ |
490 |
491 |
492 |
493 | do_cat( char *f, int fd) |
494 |
495 | { |
496 |
497 | char *extension = file_type(f); |
498 |
499 | char *content = "text/plain" ; |
500 |
501 | FILE *fpsock, *fpfile; |
502 |
503 | int c; |
504 |
505 |
506 |
507 | if ( strcmp (extension, "html" ) == 0 ) |
508 |
509 | content = "text/html" ; |
510 |
511 | else if ( strcmp (extension, "gif" ) == 0 ) |
512 |
513 | content = "image/gif" ; |
514 |
515 | else if ( strcmp (extension, "jpg" ) == 0 ) |
516 |
517 | content = "image/jpeg" ; |
518 |
519 | else if ( strcmp (extension, "jpeg" ) == 0 ) |
520 |
521 | content = "image/jpeg" ; |
522 |
523 |
524 |
525 | fpsock = fdopen(fd, "w" ); |
526 |
527 | fpfile = fopen ( f , "r" ); |
528 |
529 | if ( fpsock != NULL && fpfile != NULL ) |
530 |
531 | { |
532 |
533 | header( fpsock, content ); |
534 |
535 | fprintf (fpsock, "\r\n" ); |
536 |
537 | while ( (c = getc (fpfile) ) != EOF ) |
538 |
539 | putc (c, fpsock); |
540 |
541 | fclose (fpfile); |
542 |
543 | fclose (fpsock); |
544 |
545 | } |
546 |
547 | exit (0); |
548 |
549 | } |