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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations)
Sat Sep 28 10:05:00 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.12: +6 -5 lines
File MIME type: text/plain
Improved HIC support. Now queues are used, instead of pipes for IPC. This avoids hanging the server, if the pipe was full.

1 nmav 1.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 nmav 1.13 /* $Id: request.c,v 1.12 2002/09/27 21:09:11 nmav Exp $*/
25 nmav 1.1
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 nmav 1.3 static pthread_mutex_t accept_mutex[2] = {
70     PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
71 nmav 1.1 #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 nmav 1.5 void get_request(server_params* params, socket_type *server_s)
81 nmav 1.1 {
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 nmav 1.3 /* 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 nmav 1.5 pthread_mutex_lock( &accept_mutex[ server_s->secure]);
99 nmav 1.1 #endif
100 nmav 1.5 fd = accept(server_s->socket, (struct sockaddr *) &remote_addr,
101 nmav 1.1 &remote_addrlen);
102    
103     #ifdef ENABLE_SMP
104 nmav 1.7 /* No dead lock conditions here, since accept() is non blocking.
105     */
106 nmav 1.5 pthread_mutex_unlock( &accept_mutex[ server_s->secure]);
107 nmav 1.1 #endif
108    
109     if (fd == -1) {
110     if (errno != EAGAIN && errno != EWOULDBLOCK)
111     /* abnormal error */
112     WARN("accept");
113     else
114     /* no requests */
115 nmav 1.5 server_s->pending_requests = 0;
116 nmav 1.1 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 nmav 1.5 if ( server_s->secure) {
160 nmav 1.1 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 nmav 1.5 if (server_s->secure != 0) conn->secure = 1;
188 nmav 1.1 else conn->secure = 0;
189    
190 nmav 1.5 if ( server_s->secure != 0)
191 nmav 1.1 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 nmav 1.7
200     if (default_document_root)
201     memcpy( conn->document_root, default_document_root, default_document_root_size + 1);
202 nmav 1.1
203 nmav 1.8 if (server_name)
204     conn->hostname = server_name;
205    
206 nmav 1.1 /* 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 nmav 1.5 #ifdef HAVE_TCP_CORK
253 nmav 1.1 {
254     int one = 1;
255 nmav 1.5 if (setsockopt(conn->fd, IPPROTO_TCP, TCP_CORK,
256 nmav 1.1 (void *) &one, sizeof (one)) == -1) {
257 nmav 1.5 WARN("setsockopt: unable to set TCP_CORK");
258 nmav 1.1 }
259    
260     }
261 nmav 1.5 #endif /* TCP_CORK */
262    
263 nmav 1.1
264     #ifndef NO_RATE_LIMIT
265     if (conn->fd > max_connections) {
266     send_r_service_unavailable(conn);
267     conn->status = DONE;
268 nmav 1.5 server_s->pending_requests = 0;
269 nmav 1.1 }
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 nmav 1.5 /* Needed when TCP_CORK is used... */
448     socket_flush( req->fd);
449 nmav 1.1
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 nmav 1.5 void process_requests(server_params* params, socket_type *server_s)
470 nmav 1.1 {
471     int retval = 0;
472     request *current, *trailer;
473    
474 nmav 1.5 if (server_s->pending_requests) {
475 nmav 1.1 get_request(params, server_s);
476     #ifdef ORIGINAL_BEHAVIOR
477 nmav 1.5 server_s->pending_requests = 0;
478 nmav 1.1 #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 nmav 1.5 if (server_s->pending_requests)
569 nmav 1.1 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 nmav 1.2 #define SIMPLE_HTTP_VERSION "HTTP/0.9"
607 nmav 1.1 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 nmav 1.12 if (req->post_data_fd == -1)
730 nmav 1.1 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 nmav 1.4 /* Parses HTTP/1.1 range values.
743     */
744     static int parse_range( const char* value, unsigned long *p1, unsigned long *p2)
745     {
746 nmav 1.13 int ret = 0;
747 nmav 1.4 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 nmav 1.13 if (value[0] == '-') {
765     *p2 = boa_atol( &value[1]);
766     return 0;
767     } else
768 nmav 1.4 ret = sscanf( value, "%lu-%lu", p1, p2);
769    
770     if (ret == 1) {
771     /* This one accepts ranges of both "-stop" and "start-"
772     */
773     return 0;
774     }
775    
776     if (ret == 2)
777     return 0;
778    
779     return -1;
780     }
781    
782 nmav 1.8 inline
783     static void init_range_stuff( request* req, char* value)
784     {
785     unsigned long int p1, p2;
786     if (parse_range( value, &p1, &p2) == 0) {
787     req->range_start = p1;
788     req->range_stop = p2;
789     } else {
790     req->range_start = 0;
791     req->range_stop = 0;
792     log_error_time();
793     fprintf(stderr, "bogus range: \"%s\"\n", value);
794     send_r_bad_request(req);
795     }
796     }
797    
798     inline
799     static void init_vhost_stuff( request* req, char* value)
800     {
801     virthost* vhost;
802     int valuelen;
803    
804     valuelen = strlen(value);
805    
806     vhost = find_virthost( value, valuelen);
807    
808     if ( vhost && ( vhost->ip == NULL || !memcmp( vhost->ip, req->local_ip_addr, vhost->ip_len) ))
809     {
810     req->hostname = value;
811     memcpy( req->document_root, vhost->document_root, vhost->document_root_len + 1);
812     if (vhost->user_dir)
813     memcpy( req->user_dir, vhost->user_dir, vhost->user_dir_len + 1);
814    
815     } else { /* No virtual host found. use defaults */
816     if ( default_document_root)
817     memcpy( req->document_root, default_document_root, default_document_root_size + 1);
818     }
819     }
820 nmav 1.4
821 nmav 1.1 /*
822     * Name: process_option_line
823     *
824     * Description: Parses the contents of req->header_line and takes
825     * appropriate action.
826     */
827    
828     int process_option_line(request * req)
829     {
830     char c, *value, *line = req->header_line;
831    
832     /* Start by aggressively hacking the in-place copy of the header line */
833    
834     #ifdef FASCIST_LOGGING
835     log_error_time();
836     fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
837     #endif
838    
839     value = strchr(line, ':');
840     if (value == NULL)
841     return 0;
842     *value++ = '\0'; /* overwrite the : */
843     to_upper(line); /* header types are case-insensitive */
844     while ((c = *value) && (c == ' ' || c == '\t'))
845     value++;
846    
847     if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
848     req->if_modified_since = value;
849    
850     else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
851     req->content_type = value;
852    
853     else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
854     req->content_length = value;
855    
856     else if (!memcmp(line, "CONNECTION", 11) &&
857     ka_max && req->keepalive != KA_STOPPED) {
858     req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
859     KA_ACTIVE : KA_STOPPED);
860     }
861     /* #ifdef ACCEPT_ON */
862     else if (!memcmp(line, "ACCEPT", 7))
863     add_accept_header(req, value);
864     /* #endif */
865    
866     /* Need agent and referer for logs */
867     else if (!memcmp(line, "REFERER", 8)) {
868     req->header_referer = value;
869     if (!add_cgi_env(req, "REFERER", value, 1))
870     return 0;
871     } else if (!memcmp(line, "USER_AGENT", 11)) {
872     req->header_user_agent = value;
873     if (!add_cgi_env(req, "USER_AGENT", value, 1))
874 nmav 1.4 return 0;
875     } else if (!memcmp(line, "RANGE", 5)) {
876 nmav 1.8 init_range_stuff( req, value);
877 nmav 1.6 } else if (!memcmp(line, "HOST", 4)) {
878 nmav 1.8 init_vhost_stuff( req, value);
879 nmav 1.10 if (!add_cgi_env(req, "HOST", value, 1))
880     return 0;
881 nmav 1.1 } else {
882     if (!add_cgi_env(req, line, value, 1))
883     return 0;
884     }
885     return 1;
886     }
887    
888     /*
889     * Name: add_accept_header
890     * Description: Adds a mime_type to a requests accept char buffer
891     * silently ignore any that don't fit -
892     * shouldn't happen because of relative buffer sizes
893     */
894    
895     void add_accept_header(request * req, char *mime_type)
896     {
897     #ifdef ACCEPT_ON
898     int l = strlen(req->accept);
899     int l2 = strlen(mime_type);
900    
901     if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
902     return;
903    
904     if (req->accept[0] == '\0')
905     strcpy(req->accept, mime_type);
906     else {
907     req->accept[l] = ',';
908     req->accept[l + 1] = ' ';
909     memcpy(req->accept + l + 2, mime_type, l2 + 1);
910     /* the +1 is for the '\0' */
911     /*
912     sprintf(req->accept + l, ", %s", mime_type);
913     */
914     }
915     #endif
916     }
917    
918     void free_requests(server_params* params)
919     {
920     request *ptr, *next;
921    
922     ptr = params->request_free;
923     while (ptr != NULL) {
924     next = ptr->next;
925     free(ptr);
926     ptr = next;
927     }
928     params->request_free = NULL;
929     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26