/[hydra]/hydra/src/request.c
ViewVC logotype

Contents of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Fri Sep 27 07:03:45 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.8: +1 -5 lines
File MIME type: text/plain
Added locks in the SSL session cache.

1 /*
2 * Boa, an http server
3 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4 * Some changes Copyright (C) 1996,97 Larry Doolittle <ldoolitt@boa.org>
5 * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
6 * Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 */
23
24 /* $Id: request.c,v 1.8 2002/09/25 06:42:34 nmav Exp $*/
25
26 #include "boa.h"
27 #include <stddef.h> /* for offsetof */
28 #include "ssl.h"
29 #include "socket.h"
30
31 extern int boa_ssl;
32
33 /* function prototypes located in this file only */
34 static void free_request( server_params* params, request ** list_head_addr,
35 request * req);
36
37 /*
38 * Name: new_request
39 * Description: Obtains a request struct off the free list, or if the
40 * free list is empty, allocates memory
41 *
42 * Return value: pointer to initialized request
43 */
44
45 request *new_request(server_params* params)
46 {
47 request *req;
48
49 if (params->request_free) {
50 req = params->request_free; /* first on free list */
51 dequeue(&params->request_free, params->request_free); /* dequeue the head */
52 } else {
53 req = (request *) malloc(sizeof (request));
54 if (!req) {
55 log_error_time();
56 perror("malloc for new request");
57 return NULL;
58 }
59 }
60
61 memset(req, 0, offsetof(request, buffer) + 1);
62 req->data_fd = -1;
63 req->post_data_fd = -1;
64
65 return req;
66 }
67
68 #ifdef ENABLE_SMP
69 static pthread_mutex_t accept_mutex[2] = {
70 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
71 #endif
72
73 /*
74 * Name: get_request
75 *
76 * Description: Polls the server socket for a request. If one exists,
77 * does some basic initialization and adds it to the ready queue;.
78 */
79
80 void get_request(server_params* params, socket_type *server_s)
81 {
82 int fd; /* socket */
83 struct SOCKADDR remote_addr; /* address */
84 struct SOCKADDR salocal;
85 int remote_addrlen = sizeof (struct SOCKADDR);
86 request *conn; /* connection */
87 size_t len;
88 static int system_bufsize = 0; /* Default size of SNDBUF given by system */
89 gnutls_session ssl_state = NULL;
90
91 remote_addr.S_FAMILY = 0xdead;
92
93 #ifdef ENABLE_SMP
94 /* here we make use of the fact that server_s.secure is
95 * 0 or 1, and we have 2 mutexes, one for the secure port,
96 * and one of the normal http port.
97 */
98 pthread_mutex_lock( &accept_mutex[ server_s->secure]);
99 #endif
100 fd = accept(server_s->socket, (struct sockaddr *) &remote_addr,
101 &remote_addrlen);
102
103 #ifdef ENABLE_SMP
104 /* No dead lock conditions here, since accept() is non blocking.
105 */
106 pthread_mutex_unlock( &accept_mutex[ server_s->secure]);
107 #endif
108
109 if (fd == -1) {
110 if (errno != EAGAIN && errno != EWOULDBLOCK)
111 /* abnormal error */
112 WARN("accept");
113 else
114 /* no requests */
115 server_s->pending_requests = 0;
116 return;
117 }
118 if (fd >= FD_SETSIZE) {
119 WARN("Got fd >= FD_SETSIZE.");
120 close(fd);
121 return;
122 }
123 #ifdef DEBUGNONINET
124 /* This shows up due to race conditions in some Linux kernels
125 when the client closes the socket sometime between
126 the select() and accept() syscalls.
127 Code and description by Larry Doolittle <ldoolitt@boa.org>
128 */
129 #define HEX(x) (((x)>9)?(('a'-10)+(x)):('0'+(x)))
130 if (remote_addr.sin_family != AF_INET) {
131 struct sockaddr *bogus = (struct sockaddr *) &remote_addr;
132 char *ap, ablock[44];
133 int i;
134 close(fd);
135 log_error_time();
136 for (ap = ablock, i = 0; i < remote_addrlen && i < 14; i++) {
137 *ap++ = ' ';
138 *ap++ = HEX((bogus->sa_data[i] >> 4) & 0x0f);
139 *ap++ = HEX(bogus->sa_data[i] & 0x0f);
140 }
141 *ap = '\0';
142 fprintf(stderr, "non-INET connection attempt: socket %d, "
143 "sa_family = %hu, sa_data[%d] = %s\n",
144 fd, bogus->sa_family, remote_addrlen, ablock);
145 return;
146 }
147 #endif
148
149 /* XXX Either delete this, or document why it's needed */
150 /* Pointed out 3-Oct-1999 by Paul Saab <paul@mu.org> */
151 #ifdef REUSE_EACH_CLIENT_CONNECTION_SOCKET
152 if ((setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
153 sizeof (sock_opt))) == -1) {
154 DIE("setsockopt: unable to set SO_REUSEADDR");
155 }
156 #endif
157
158 #ifdef ENABLE_SSL
159 if ( server_s->secure) {
160 ssl_state = initialize_ssl_session();
161 if (ssl_state == NULL) {
162 WARN("Could not initialize ssl state.");
163 close(fd);
164 return;
165 }
166
167 gnutls_transport_set_ptr( ssl_state, fd);
168 }
169 #endif
170
171 len = sizeof(salocal);
172
173 if (getsockname(fd, (struct sockaddr *) &salocal, &len) != 0) {
174 WARN("getsockname");
175 close(fd);
176 return;
177 }
178
179 conn = new_request( params);
180 if (!conn) {
181 close(fd);
182 return;
183 }
184 conn->fd = fd;
185 conn->ssl_state = ssl_state;
186
187 if (server_s->secure != 0) conn->secure = 1;
188 else conn->secure = 0;
189
190 if ( server_s->secure != 0)
191 conn->status = FINISH_HANDSHAKE;
192 else conn->status = READ_HEADER;
193
194 conn->header_line = conn->client_stream;
195 conn->time_last = current_time;
196 conn->kacount = ka_max;
197
198 ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);
199
200 if (default_document_root)
201 memcpy( conn->document_root, default_document_root, default_document_root_size + 1);
202
203 if (server_name)
204 conn->hostname = server_name;
205
206 /* nonblocking socket */
207 if (set_nonblock_fd(conn->fd) == -1)
208 WARN("fcntl: unable to set new socket to non-block");
209
210 /* set close on exec to true */
211 if (fcntl(conn->fd, F_SETFD, 1) == -1)
212 WARN("fctnl: unable to set close-on-exec for new socket");
213
214 /* Increase buffer size if we have to.
215 * Only ask the system the buffer size on the first request,
216 * and assume all subsequent sockets have the same size.
217 */
218 if (system_bufsize == 0) {
219 len = sizeof (system_bufsize);
220 if (getsockopt
221 (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
222 && len == sizeof (system_bufsize)) {
223 /*
224 fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",
225 get_commonlog_time(), system_bufsize);
226 */
227 ;
228 } else {
229 WARN("getsockopt(SNDBUF)");
230 system_bufsize = 1;
231 }
232 }
233 if (system_bufsize < params->sockbufsize) {
234 if (setsockopt
235 (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &params->sockbufsize,
236 sizeof (params->sockbufsize)) == -1) {
237 WARN("setsockopt: unable to set socket buffer size");
238 #ifdef DIE_ON_ERROR_TUNING_SNDBUF
239 exit(errno);
240 #endif
241 }
242 }
243
244 /* for log file and possible use by CGI programs */
245 ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
246
247 /* for possible use by CGI programs */
248 conn->remote_port = net_port(&remote_addr);
249
250 params->status.requests++;
251
252 #ifdef HAVE_TCP_CORK
253 {
254 int one = 1;
255 if (setsockopt(conn->fd, IPPROTO_TCP, TCP_CORK,
256 (void *) &one, sizeof (one)) == -1) {
257 WARN("setsockopt: unable to set TCP_CORK");
258 }
259
260 }
261 #endif /* TCP_CORK */
262
263
264 #ifndef NO_RATE_LIMIT
265 if (conn->fd > max_connections) {
266 send_r_service_unavailable(conn);
267 conn->status = DONE;
268 server_s->pending_requests = 0;
269 }
270 #endif /* NO_RATE_LIMIT */
271
272 params->total_connections++;
273
274 enqueue(&params->request_ready, conn);
275 }
276
277
278 /*
279 * Name: free_request
280 *
281 * Description: Deallocates memory for a finished request and closes
282 * down socket.
283 */
284
285 static void free_request( server_params *params, request ** list_head_addr, request * req)
286 {
287 int i;
288 /* free_request should *never* get called by anything but
289 process_requests */
290
291 if (req->buffer_end && req->status != DEAD) {
292 req->status = DONE;
293 return;
294 }
295 /* put request on the free list */
296 dequeue(list_head_addr, req); /* dequeue from ready or block list */
297
298 if (req->logline) /* access log */
299 log_access(req);
300
301 if (req->mmap_entry_var)
302 release_mmap( req->mmap_entry_var);
303 /* FIXME: Why is it needed? */ else if (req->data_mem)
304 munmap(req->data_mem, req->filesize);
305
306 if (req->data_fd != -1)
307 close(req->data_fd);
308
309 if (req->post_data_fd != -1)
310 close(req->post_data_fd);
311
312 if (req->response_status >= 400)
313 params->status.errors++;
314
315 for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) {
316 if (req->cgi_env[i]) {
317 free(req->cgi_env[i]);
318 } else {
319 log_error_time();
320 fprintf(stderr, "Warning: CGI Environment contains NULL value" \
321 "(index %d of %d).\n", i, req->cgi_env_index);
322 }
323 }
324
325 if (req->pathname)
326 free(req->pathname);
327 if (req->path_info)
328 free(req->path_info);
329 if (req->path_translated)
330 free(req->path_translated);
331 if (req->script_name)
332 free(req->script_name);
333
334 if ((req->keepalive == KA_ACTIVE) &&
335 (req->response_status < 500) && req->kacount > 0) {
336 int bytes_to_move;
337
338 request *conn = new_request( params);
339 if (!conn) {
340 /* errors already reported */
341 enqueue(&params->request_free, req);
342 close(req->fd);
343 params->total_connections--;
344 return;
345 }
346 conn->fd = req->fd;
347
348 #ifdef ENABLE_SSL
349 if ( req->secure != 0) {
350 conn->ssl_state = initialize_ssl_session();
351 conn->secure = 1;
352
353 if (conn->ssl_state == NULL) {
354 enqueue(&params->request_free, req);
355 close(req->fd);
356 params->total_connections--;
357 return;
358 }
359
360 gnutls_transport_set_ptr( conn->ssl_state, conn->fd);
361 conn->status = FINISH_HANDSHAKE;
362 } else {
363 #endif
364 conn->secure = 0;
365 conn->ssl_state = NULL;
366 conn->status = READ_HEADER;
367 #ifdef ENABLE_SSL
368 }
369 #endif
370
371 conn->header_line = conn->client_stream;
372 conn->kacount = req->kacount - 1;
373
374 /* close enough and we avoid a call to time(NULL) */
375 conn->time_last = req->time_last;
376
377 /* for log file and possible use by CGI programs */
378 memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
379 memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST);
380
381 /* for possible use by CGI programs */
382 conn->remote_port = req->remote_port;
383
384 params->status.requests++;
385
386 /* we haven't parsed beyond req->parse_pos, so... */
387 bytes_to_move = req->client_stream_pos - req->parse_pos;
388
389 if (bytes_to_move) {
390 memcpy(conn->client_stream,
391 req->client_stream + req->parse_pos, bytes_to_move);
392 conn->client_stream_pos = bytes_to_move;
393 }
394 enqueue(&params->request_block, conn);
395
396 BOA_FD_SET(conn->fd, &params->block_read_fdset);
397
398 enqueue(&params->request_free, req);
399
400 return;
401 }
402
403 /*
404 While debugging some weird errors, Jon Nelson learned that
405 some versions of Netscape Navigator break the
406 HTTP specification.
407
408 Some research on the issue brought up:
409
410 http://www.apache.org/docs/misc/known_client_problems.html
411
412 As quoted here:
413
414 "
415 Trailing CRLF on POSTs
416
417 This is a legacy issue. The CERN webserver required POST
418 data to have an extra CRLF following it. Thus many
419 clients send an extra CRLF that is not included in the
420 Content-Length of the request. Apache works around this
421 problem by eating any empty lines which appear before a
422 request.
423 "
424
425 Boa will (for now) hack around this stupid bug in Netscape
426 (and Internet Exploder)
427 by reading up to 32k after the connection is all but closed.
428 This should eliminate any remaining spurious crlf sent
429 by the client.
430
431 Building bugs *into* software to be compatable is
432 just plain wrong
433 */
434
435 if (req->method == M_POST) {
436 char buf[32768];
437
438 socket_recv( req, buf, sizeof(buf));
439 }
440
441 #ifdef ENABLE_SSL
442 if ( req->secure) {
443 gnutls_bye(req->ssl_state, GNUTLS_SHUT_WR);
444 gnutls_deinit( req->ssl_state);
445 }
446 #endif
447 /* Needed when TCP_CORK is used... */
448 socket_flush( req->fd);
449
450 close(req->fd);
451
452 params->total_connections--;
453
454 enqueue(&params->request_free, req);
455
456 return;
457 }
458
459 /*
460 * Name: process_requests
461 *
462 * Description: Iterates through the ready queue, passing each request
463 * to the appropriate handler for processing. It monitors the
464 * return value from handler functions, all of which return -1
465 * to indicate a block, 0 on completion and 1 to remain on the
466 * ready list for more procesing.
467 */
468
469 void process_requests(server_params* params, socket_type *server_s)
470 {
471 int retval = 0;
472 request *current, *trailer;
473
474 if (server_s->pending_requests) {
475 get_request(params, server_s);
476 #ifdef ORIGINAL_BEHAVIOR
477 server_s->pending_requests = 0;
478 #endif
479 }
480
481 current = params->request_ready;
482
483 while (current) {
484 time(&current_time);
485 if (current->buffer_end && /* there is data in the buffer */
486 current->status != DEAD && current->status != DONE) {
487 retval = req_flush(current);
488 /*
489 * retval can be -2=error, -1=blocked, or bytes left
490 */
491 if (retval == -2) { /* error */
492 current->status = DEAD;
493 retval = 0;
494 } else if (retval >= 0) {
495 /* notice the >= which is different from below?
496 Here, we may just be flushing headers.
497 We don't want to return 0 because we are not DONE
498 or DEAD */
499
500 retval = 1;
501 }
502 } else {
503 switch (current->status) {
504 #ifdef ENABLE_SSL
505 case FINISH_HANDSHAKE:
506 retval = finish_handshake( current);
507 break;
508 case SEND_ALERT:
509 retval = send_alert( current);
510 break;
511 #endif
512 case READ_HEADER:
513 case ONE_CR:
514 case ONE_LF:
515 case TWO_CR:
516 retval = read_header(params, current);
517 break;
518 case BODY_READ:
519 retval = read_body(current);
520 break;
521 case BODY_WRITE:
522 retval = write_body(current);
523 break;
524 case WRITE:
525 retval = process_get(params, current);
526 break;
527 case PIPE_READ:
528 retval = read_from_pipe(current);
529 break;
530 case PIPE_WRITE:
531 retval = write_from_pipe(current);
532 break;
533 case DONE:
534 /* a non-status that will terminate the request */
535 retval = req_flush(current);
536 /*
537 * retval can be -2=error, -1=blocked, or bytes left
538 */
539 if (retval == -2) { /* error */
540 current->status = DEAD;
541 retval = 0;
542 } else if (retval > 0) {
543 retval = 1;
544 }
545 break;
546 case DEAD:
547 retval = 0;
548 current->buffer_end = 0;
549 SQUASH_KA(current);
550 break;
551 default:
552 retval = 0;
553 fprintf(stderr, "Unknown status (%d), "
554 "closing!\n", current->status);
555 current->status = DEAD;
556 break;
557 }
558
559 }
560
561 if (params->sigterm_flag)
562 SQUASH_KA(current);
563
564 /* we put this here instead of after the switch so that
565 * if we are on the last request, and get_request is successful,
566 * current->next is valid!
567 */
568 if (server_s->pending_requests)
569 get_request(params, server_s);
570
571 switch (retval) {
572 case -1: /* request blocked */
573 trailer = current;
574 current = current->next;
575 block_request(params, trailer);
576 break;
577 case 0: /* request complete */
578 current->time_last = current_time;
579 trailer = current;
580 current = current->next;
581 free_request(params, &params->request_ready, trailer);
582 break;
583 case 1: /* more to do */
584 current->time_last = current_time;
585 current = current->next;
586 break;
587 default:
588 log_error_time();
589 fprintf(stderr, "Unknown retval in process.c - "
590 "Status: %d, retval: %d\n", current->status, retval);
591 current = current->next;
592 break;
593 }
594 }
595 }
596
597 /*
598 * Name: process_logline
599 *
600 * Description: This is called with the first req->header_line received
601 * by a request, called "logline" because it is logged to a file.
602 * It is parsed to determine request type and method, then passed to
603 * translate_uri for further parsing. Also sets up CGI environment if
604 * needed.
605 */
606 #define SIMPLE_HTTP_VERSION "HTTP/0.9"
607 int process_logline(request * req)
608 {
609 char *stop, *stop2;
610
611 req->logline = req->client_stream;
612 if (!memcmp(req->logline, "GET ", 4))
613 req->method = M_GET;
614 else if (!memcmp(req->logline, "HEAD ", 5))
615 /* head is just get w/no body */
616 req->method = M_HEAD;
617 else if (!memcmp(req->logline, "POST ", 5))
618 req->method = M_POST;
619 else {
620 log_error_time();
621 fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
622 send_r_not_implemented(req);
623 return 0;
624 }
625
626 req->http_version = SIMPLE_HTTP_VERSION;
627 req->simple = 1;
628
629 /* Guaranteed to find ' ' since we matched a method above */
630 stop = req->logline + 3;
631 if (*stop != ' ')
632 ++stop;
633
634 /* scan to start of non-whitespace */
635 while (*(++stop) == ' ');
636
637 stop2 = stop;
638
639 /* scan to end of non-whitespace */
640 while (*stop2 != '\0' && *stop2 != ' ')
641 ++stop2;
642
643 if (stop2 - stop > MAX_HEADER_LENGTH) {
644 log_error_time();
645 fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
646 req->logline);
647 send_r_bad_request(req);
648 return 0;
649 }
650 memcpy(req->request_uri, stop, stop2 - stop);
651 req->request_uri[stop2 - stop] = '\0';
652
653 if (*stop2 == ' ') {
654 /* if found, we should get an HTTP/x.x */
655 unsigned int p1, p2;
656
657 /* scan to end of whitespace */
658 ++stop2;
659 while (*stop2 == ' ' && *stop2 != '\0')
660 ++stop2;
661
662 /* scan in HTTP/major.minor */
663 if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {
664 /* HTTP/{0.9,1.0,1.1} */
665 if (p1 == 1 && (p2 == 0 || p2 == 1)) {
666 req->http_version = stop2;
667 req->simple = 0;
668 } else if (p1 > 1 || (p1 != 0 && p2 > 1)) {
669 goto BAD_VERSION;
670 }
671 } else {
672 goto BAD_VERSION;
673 }
674 }
675
676 if (req->method == M_HEAD && req->simple) {
677 send_r_bad_request(req);
678 return 0;
679 }
680 req->cgi_env_index = COMMON_CGI_COUNT;
681
682 return 1;
683
684 BAD_VERSION:
685 log_error_time();
686 fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
687 send_r_bad_request(req);
688 return 0;
689 }
690
691 /*
692 * Name: process_header_end
693 *
694 * Description: takes a request and performs some final checking before
695 * init_cgi or init_get
696 * Returns 0 for error or NPH, or 1 for success
697 */
698
699 int process_header_end(server_params* params, request * req)
700 {
701 if (!req->logline) {
702 send_r_error(req);
703 return 0;
704 }
705
706 /* Percent-decode request */
707 if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
708 log_error_doc(req);
709 fputs("Problem unescaping uri\n", stderr);
710 send_r_bad_request(req);
711 return 0;
712 }
713
714 /* clean pathname */
715 clean_pathname(req->request_uri);
716
717 if (req->request_uri[0] != '/') {
718 send_r_bad_request(req);
719 return 0;
720 }
721
722 if (translate_uri(req) == 0) { /* unescape, parse uri */
723 SQUASH_KA(req);
724 return 0; /* failure, close down */
725 }
726
727 if (req->method == M_POST) {
728 req->post_data_fd = create_temporary_file(1, NULL, 0);
729 if (req->post_data_fd == 0)
730 return(0);
731 return(1); /* success */
732 }
733
734 if (req->is_cgi) {
735 return init_cgi(req);
736 }
737
738 req->status = WRITE;
739 return init_get(params, req); /* get and head */
740 }
741
742 /* Parses HTTP/1.1 range values.
743 */
744 static int parse_range( const char* value, unsigned long *p1, unsigned long *p2)
745 {
746 int ret;
747 int len;
748
749 *p1 = *p2 = 0;
750
751 len = strlen( value);
752 if (len < 7) return -1;
753
754 /* we do not accept ranges of the form 10-20,21-30
755 */
756 if (strchr( value, ',') != NULL) return -1;
757
758 if ( memcmp("bytes=", value, 6) != 0) {
759 return -1;
760 } else value += 6;
761
762 if (strchr( value, '-') == NULL) return -1;
763
764 if (value[0] == '-')
765 ret = sscanf( value, "-%lu", p2);
766 else
767 ret = sscanf( value, "%lu-%lu", p1, p2);
768
769 if (ret == 1) {
770 /* This one accepts ranges of both "-stop" and "start-"
771 */
772 return 0;
773 }
774
775 if (ret == 2)
776 return 0;
777
778 return -1;
779 }
780
781 inline
782 static void init_range_stuff( request* req, char* value)
783 {
784 unsigned long int p1, p2;
785 if (parse_range( value, &p1, &p2) == 0) {
786 req->range_start = p1;
787 req->range_stop = p2;
788 } else {
789 req->range_start = 0;
790 req->range_stop = 0;
791 log_error_time();
792 fprintf(stderr, "bogus range: \"%s\"\n", value);
793 send_r_bad_request(req);
794 }
795 }
796
797 inline
798 static void init_vhost_stuff( request* req, char* value)
799 {
800 virthost* vhost;
801 int valuelen;
802
803 valuelen = strlen(value);
804
805 vhost = find_virthost( value, valuelen);
806
807 if ( vhost && ( vhost->ip == NULL || !memcmp( vhost->ip, req->local_ip_addr, vhost->ip_len) ))
808 {
809 req->hostname = value;
810 memcpy( req->document_root, vhost->document_root, vhost->document_root_len + 1);
811 if (vhost->user_dir)
812 memcpy( req->user_dir, vhost->user_dir, vhost->user_dir_len + 1);
813
814 } else { /* No virtual host found. use defaults */
815 if ( default_document_root)
816 memcpy( req->document_root, default_document_root, default_document_root_size + 1);
817 }
818 }
819
820 /*
821 * Name: process_option_line
822 *
823 * Description: Parses the contents of req->header_line and takes
824 * appropriate action.
825 */
826
827 int process_option_line(request * req)
828 {
829 char c, *value, *line = req->header_line;
830
831 /* Start by aggressively hacking the in-place copy of the header line */
832
833 #ifdef FASCIST_LOGGING
834 log_error_time();
835 fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
836 #endif
837
838 value = strchr(line, ':');
839 if (value == NULL)
840 return 0;
841 *value++ = '\0'; /* overwrite the : */
842 to_upper(line); /* header types are case-insensitive */
843 while ((c = *value) && (c == ' ' || c == '\t'))
844 value++;
845
846 if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
847 req->if_modified_since = value;
848
849 else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
850 req->content_type = value;
851
852 else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
853 req->content_length = value;
854
855 else if (!memcmp(line, "CONNECTION", 11) &&
856 ka_max && req->keepalive != KA_STOPPED) {
857 req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
858 KA_ACTIVE : KA_STOPPED);
859 }
860 /* #ifdef ACCEPT_ON */
861 else if (!memcmp(line, "ACCEPT", 7))
862 add_accept_header(req, value);
863 /* #endif */
864
865 /* Need agent and referer for logs */
866 else if (!memcmp(line, "REFERER", 8)) {
867 req->header_referer = value;
868 if (!add_cgi_env(req, "REFERER", value, 1))
869 return 0;
870 } else if (!memcmp(line, "USER_AGENT", 11)) {
871 req->header_user_agent = value;
872 if (!add_cgi_env(req, "USER_AGENT", value, 1))
873 return 0;
874 } else if (!memcmp(line, "RANGE", 5)) {
875 init_range_stuff( req, value);
876 } else if (!memcmp(line, "HOST", 4)) {
877 init_vhost_stuff( req, value);
878 } else {
879 if (!add_cgi_env(req, line, value, 1))
880 return 0;
881 }
882 return 1;
883 }
884
885 /*
886 * Name: add_accept_header
887 * Description: Adds a mime_type to a requests accept char buffer
888 * silently ignore any that don't fit -
889 * shouldn't happen because of relative buffer sizes
890 */
891
892 void add_accept_header(request * req, char *mime_type)
893 {
894 #ifdef ACCEPT_ON
895 int l = strlen(req->accept);
896 int l2 = strlen(mime_type);
897
898 if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
899 return;
900
901 if (req->accept[0] == '\0')
902 strcpy(req->accept, mime_type);
903 else {
904 req->accept[l] = ',';
905 req->accept[l + 1] = ' ';
906 memcpy(req->accept + l + 2, mime_type, l2 + 1);
907 /* the +1 is for the '\0' */
908 /*
909 sprintf(req->accept + l, ", %s", mime_type);
910 */
911 }
912 #endif
913 }
914
915 void free_requests(server_params* params)
916 {
917 request *ptr, *next;
918
919 ptr = params->request_free;
920 while (ptr != NULL) {
921 next = ptr->next;
922 free(ptr);
923 ptr = next;
924 }
925 params->request_free = NULL;
926 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26