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

Contents of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations)
Mon Sep 23 12:48:59 2002 UTC (21 years, 7 months ago) by nmav
Branch: MAIN
Changes since 1.3: +55 -1 lines
File MIME type: text/plain
Added limited support for HTTP/1.1 ranges.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26