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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations)
Tue Sep 24 17:12:47 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.5: +32 -2 lines
File MIME type: text/plain
Added some support for host based virtual hosting.

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.6 /* $Id: request.c,v 1.5 2002/09/23 17:56:41 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     #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 nmav 1.3 static pthread_mutex_t accept_mutex[2] = {
74     PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER };
75 nmav 1.1 #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 nmav 1.5 void get_request(server_params* params, socket_type *server_s)
85 nmav 1.1 {
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 nmav 1.3 /* 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 nmav 1.5 pthread_mutex_lock( &accept_mutex[ server_s->secure]);
103 nmav 1.1 #endif
104    
105 nmav 1.5 fd = accept(server_s->socket, (struct sockaddr *) &remote_addr,
106 nmav 1.1 &remote_addrlen);
107    
108     #ifdef ENABLE_SMP
109 nmav 1.5 pthread_mutex_unlock( &accept_mutex[ server_s->secure]);
110 nmav 1.1 #endif
111    
112     if (fd == -1) {
113     if (errno != EAGAIN && errno != EWOULDBLOCK)
114     /* abnormal error */
115     WARN("accept");
116     else
117     /* no requests */
118 nmav 1.5 server_s->pending_requests = 0;
119 nmav 1.1 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 nmav 1.5 if ( server_s->secure) {
163 nmav 1.1 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 nmav 1.5 if (server_s->secure != 0) conn->secure = 1;
191 nmav 1.1 else conn->secure = 0;
192    
193 nmav 1.5 if ( server_s->secure != 0)
194 nmav 1.1 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 nmav 1.6 conn->document_root = strdup( default_document_root);
203 nmav 1.1
204     /* nonblocking socket */
205     if (set_nonblock_fd(conn->fd) == -1)
206     WARN("fcntl: unable to set new socket to non-block");
207    
208     /* set close on exec to true */
209     if (fcntl(conn->fd, F_SETFD, 1) == -1)
210     WARN("fctnl: unable to set close-on-exec for new socket");
211    
212     /* Increase buffer size if we have to.
213     * Only ask the system the buffer size on the first request,
214     * and assume all subsequent sockets have the same size.
215     */
216     if (system_bufsize == 0) {
217     len = sizeof (system_bufsize);
218     if (getsockopt
219     (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
220     && len == sizeof (system_bufsize)) {
221     /*
222     fprintf(stderr, "%sgetsockopt reports SNDBUF %d\n",
223     get_commonlog_time(), system_bufsize);
224     */
225     ;
226     } else {
227     WARN("getsockopt(SNDBUF)");
228     system_bufsize = 1;
229     }
230     }
231     if (system_bufsize < params->sockbufsize) {
232     if (setsockopt
233     (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &params->sockbufsize,
234     sizeof (params->sockbufsize)) == -1) {
235     WARN("setsockopt: unable to set socket buffer size");
236     #ifdef DIE_ON_ERROR_TUNING_SNDBUF
237     exit(errno);
238     #endif
239     }
240     }
241    
242     /* for log file and possible use by CGI programs */
243     ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
244    
245     /* for possible use by CGI programs */
246     conn->remote_port = net_port(&remote_addr);
247    
248     params->status.requests++;
249    
250 nmav 1.5 #ifdef HAVE_TCP_CORK
251 nmav 1.1 {
252     int one = 1;
253 nmav 1.5 if (setsockopt(conn->fd, IPPROTO_TCP, TCP_CORK,
254 nmav 1.1 (void *) &one, sizeof (one)) == -1) {
255 nmav 1.5 WARN("setsockopt: unable to set TCP_CORK");
256 nmav 1.1 }
257    
258     }
259 nmav 1.5 #endif /* TCP_CORK */
260    
261 nmav 1.1
262     #ifndef NO_RATE_LIMIT
263     if (conn->fd > max_connections) {
264     send_r_service_unavailable(conn);
265     conn->status = DONE;
266 nmav 1.5 server_s->pending_requests = 0;
267 nmav 1.1 }
268     #endif /* NO_RATE_LIMIT */
269    
270     params->total_connections++;
271    
272     enqueue(&params->request_ready, conn);
273     }
274    
275    
276     /*
277     * Name: free_request
278     *
279     * Description: Deallocates memory for a finished request and closes
280     * down socket.
281     */
282    
283     static void free_request( server_params *params, request ** list_head_addr, request * req)
284     {
285     int i;
286     /* free_request should *never* get called by anything but
287     process_requests */
288    
289     if (req->buffer_end && req->status != DEAD) {
290     req->status = DONE;
291     return;
292     }
293     /* put request on the free list */
294     dequeue(list_head_addr, req); /* dequeue from ready or block list */
295    
296     if (req->logline) /* access log */
297     log_access(req);
298    
299     if (req->mmap_entry_var)
300     release_mmap( req->mmap_entry_var);
301     /* FIXME: Why is it needed? */ else if (req->data_mem)
302     munmap(req->data_mem, req->filesize);
303    
304     if (req->data_fd != -1)
305     close(req->data_fd);
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 nmav 1.6 if (req->document_root)
333     free(req->document_root);
334     if (req->user_dir)
335     free(req->user_dir);
336    
337 nmav 1.1 if ((req->keepalive == KA_ACTIVE) &&
338     (req->response_status < 500) && req->kacount > 0) {
339     int bytes_to_move;
340    
341     request *conn = new_request( params);
342     if (!conn) {
343     /* errors already reported */
344     enqueue(&params->request_free, req);
345     close(req->fd);
346     params->total_connections--;
347     return;
348     }
349     conn->fd = req->fd;
350    
351     #ifdef ENABLE_SSL
352     if ( req->secure != 0) {
353     conn->ssl_state = initialize_ssl_session();
354     conn->secure = 1;
355    
356     if (conn->ssl_state == NULL) {
357     enqueue(&params->request_free, req);
358     close(req->fd);
359     params->total_connections--;
360     return;
361     }
362    
363     gnutls_transport_set_ptr( conn->ssl_state, conn->fd);
364     conn->status = FINISH_HANDSHAKE;
365     } else {
366     #endif
367     conn->secure = 0;
368     conn->ssl_state = NULL;
369     conn->status = READ_HEADER;
370     #ifdef ENABLE_SSL
371     }
372     #endif
373    
374     conn->header_line = conn->client_stream;
375     conn->kacount = req->kacount - 1;
376    
377     /* close enough and we avoid a call to time(NULL) */
378     conn->time_last = req->time_last;
379    
380     /* for log file and possible use by CGI programs */
381     memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
382     memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST);
383    
384     /* for possible use by CGI programs */
385     conn->remote_port = req->remote_port;
386    
387     params->status.requests++;
388    
389     /* we haven't parsed beyond req->parse_pos, so... */
390     bytes_to_move = req->client_stream_pos - req->parse_pos;
391    
392     if (bytes_to_move) {
393     memcpy(conn->client_stream,
394     req->client_stream + req->parse_pos, bytes_to_move);
395     conn->client_stream_pos = bytes_to_move;
396     }
397     enqueue(&params->request_block, conn);
398    
399     BOA_FD_SET(conn->fd, &params->block_read_fdset);
400    
401     enqueue(&params->request_free, req);
402    
403     return;
404     }
405    
406     /*
407     While debugging some weird errors, Jon Nelson learned that
408     some versions of Netscape Navigator break the
409     HTTP specification.
410    
411     Some research on the issue brought up:
412    
413     http://www.apache.org/docs/misc/known_client_problems.html
414    
415     As quoted here:
416    
417     "
418     Trailing CRLF on POSTs
419    
420     This is a legacy issue. The CERN webserver required POST
421     data to have an extra CRLF following it. Thus many
422     clients send an extra CRLF that is not included in the
423     Content-Length of the request. Apache works around this
424     problem by eating any empty lines which appear before a
425     request.
426     "
427    
428     Boa will (for now) hack around this stupid bug in Netscape
429     (and Internet Exploder)
430     by reading up to 32k after the connection is all but closed.
431     This should eliminate any remaining spurious crlf sent
432     by the client.
433    
434     Building bugs *into* software to be compatable is
435     just plain wrong
436     */
437    
438     if (req->method == M_POST) {
439     char buf[32768];
440    
441     socket_recv( req, buf, sizeof(buf));
442     }
443    
444     #ifdef ENABLE_SSL
445     if ( req->secure) {
446     gnutls_bye(req->ssl_state, GNUTLS_SHUT_WR);
447     gnutls_deinit( req->ssl_state);
448     }
449     #endif
450 nmav 1.5 /* Needed when TCP_CORK is used... */
451     socket_flush( req->fd);
452 nmav 1.1
453     close(req->fd);
454    
455     params->total_connections--;
456    
457     enqueue(&params->request_free, req);
458    
459     return;
460     }
461    
462     /*
463     * Name: process_requests
464     *
465     * Description: Iterates through the ready queue, passing each request
466     * to the appropriate handler for processing. It monitors the
467     * return value from handler functions, all of which return -1
468     * to indicate a block, 0 on completion and 1 to remain on the
469     * ready list for more procesing.
470     */
471    
472 nmav 1.5 void process_requests(server_params* params, socket_type *server_s)
473 nmav 1.1 {
474     int retval = 0;
475     request *current, *trailer;
476    
477 nmav 1.5 if (server_s->pending_requests) {
478 nmav 1.1 get_request(params, server_s);
479     #ifdef ORIGINAL_BEHAVIOR
480 nmav 1.5 server_s->pending_requests = 0;
481 nmav 1.1 #endif
482     }
483    
484     current = params->request_ready;
485    
486     while (current) {
487     time(&current_time);
488     if (current->buffer_end && /* there is data in the buffer */
489     current->status != DEAD && current->status != DONE) {
490     retval = req_flush(current);
491     /*
492     * retval can be -2=error, -1=blocked, or bytes left
493     */
494     if (retval == -2) { /* error */
495     current->status = DEAD;
496     retval = 0;
497     } else if (retval >= 0) {
498     /* notice the >= which is different from below?
499     Here, we may just be flushing headers.
500     We don't want to return 0 because we are not DONE
501     or DEAD */
502    
503     retval = 1;
504     }
505     } else {
506     switch (current->status) {
507     #ifdef ENABLE_SSL
508     case FINISH_HANDSHAKE:
509     retval = finish_handshake( current);
510     break;
511     case SEND_ALERT:
512     retval = send_alert( current);
513     break;
514     #endif
515     case READ_HEADER:
516     case ONE_CR:
517     case ONE_LF:
518     case TWO_CR:
519     retval = read_header(params, current);
520     break;
521     case BODY_READ:
522     retval = read_body(current);
523     break;
524     case BODY_WRITE:
525     retval = write_body(current);
526     break;
527     case WRITE:
528     retval = process_get(params, current);
529     break;
530     case PIPE_READ:
531     retval = read_from_pipe(current);
532     break;
533     case PIPE_WRITE:
534     retval = write_from_pipe(current);
535     break;
536     case DONE:
537     /* a non-status that will terminate the request */
538     retval = req_flush(current);
539     /*
540     * retval can be -2=error, -1=blocked, or bytes left
541     */
542     if (retval == -2) { /* error */
543     current->status = DEAD;
544     retval = 0;
545     } else if (retval > 0) {
546     retval = 1;
547     }
548     break;
549     case DEAD:
550     retval = 0;
551     current->buffer_end = 0;
552     SQUASH_KA(current);
553     break;
554     default:
555     retval = 0;
556     fprintf(stderr, "Unknown status (%d), "
557     "closing!\n", current->status);
558     current->status = DEAD;
559     break;
560     }
561    
562     }
563    
564     if (params->sigterm_flag)
565     SQUASH_KA(current);
566    
567     /* we put this here instead of after the switch so that
568     * if we are on the last request, and get_request is successful,
569     * current->next is valid!
570     */
571 nmav 1.5 if (server_s->pending_requests)
572 nmav 1.1 get_request(params, server_s);
573    
574     switch (retval) {
575     case -1: /* request blocked */
576     trailer = current;
577     current = current->next;
578     block_request(params, trailer);
579     break;
580     case 0: /* request complete */
581     current->time_last = current_time;
582     trailer = current;
583     current = current->next;
584     free_request(params, &params->request_ready, trailer);
585     break;
586     case 1: /* more to do */
587     current->time_last = current_time;
588     current = current->next;
589     break;
590     default:
591     log_error_time();
592     fprintf(stderr, "Unknown retval in process.c - "
593     "Status: %d, retval: %d\n", current->status, retval);
594     current = current->next;
595     break;
596     }
597     }
598     }
599    
600     /*
601     * Name: process_logline
602     *
603     * Description: This is called with the first req->header_line received
604     * by a request, called "logline" because it is logged to a file.
605     * It is parsed to determine request type and method, then passed to
606     * translate_uri for further parsing. Also sets up CGI environment if
607     * needed.
608     */
609 nmav 1.2 #define SIMPLE_HTTP_VERSION "HTTP/0.9"
610 nmav 1.1 int process_logline(request * req)
611     {
612     char *stop, *stop2;
613    
614     req->logline = req->client_stream;
615     if (!memcmp(req->logline, "GET ", 4))
616     req->method = M_GET;
617     else if (!memcmp(req->logline, "HEAD ", 5))
618     /* head is just get w/no body */
619     req->method = M_HEAD;
620     else if (!memcmp(req->logline, "POST ", 5))
621     req->method = M_POST;
622     else {
623     log_error_time();
624     fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
625     send_r_not_implemented(req);
626     return 0;
627     }
628    
629     req->http_version = SIMPLE_HTTP_VERSION;
630     req->simple = 1;
631    
632     /* Guaranteed to find ' ' since we matched a method above */
633     stop = req->logline + 3;
634     if (*stop != ' ')
635     ++stop;
636    
637     /* scan to start of non-whitespace */
638     while (*(++stop) == ' ');
639    
640     stop2 = stop;
641    
642     /* scan to end of non-whitespace */
643     while (*stop2 != '\0' && *stop2 != ' ')
644     ++stop2;
645    
646     if (stop2 - stop > MAX_HEADER_LENGTH) {
647     log_error_time();
648     fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
649     req->logline);
650     send_r_bad_request(req);
651     return 0;
652     }
653     memcpy(req->request_uri, stop, stop2 - stop);
654     req->request_uri[stop2 - stop] = '\0';
655    
656     if (*stop2 == ' ') {
657     /* if found, we should get an HTTP/x.x */
658     unsigned int p1, p2;
659    
660     /* scan to end of whitespace */
661     ++stop2;
662     while (*stop2 == ' ' && *stop2 != '\0')
663     ++stop2;
664    
665     /* scan in HTTP/major.minor */
666     if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {
667     /* HTTP/{0.9,1.0,1.1} */
668     if (p1 == 1 && (p2 == 0 || p2 == 1)) {
669     req->http_version = stop2;
670     req->simple = 0;
671     } else if (p1 > 1 || (p1 != 0 && p2 > 1)) {
672     goto BAD_VERSION;
673     }
674     } else {
675     goto BAD_VERSION;
676     }
677     }
678    
679     if (req->method == M_HEAD && req->simple) {
680     send_r_bad_request(req);
681     return 0;
682     }
683     req->cgi_env_index = COMMON_CGI_COUNT;
684    
685     return 1;
686    
687     BAD_VERSION:
688     log_error_time();
689     fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
690     send_r_bad_request(req);
691     return 0;
692     }
693    
694     /*
695     * Name: process_header_end
696     *
697     * Description: takes a request and performs some final checking before
698     * init_cgi or init_get
699     * Returns 0 for error or NPH, or 1 for success
700     */
701    
702     int process_header_end(server_params* params, request * req)
703     {
704     if (!req->logline) {
705     send_r_error(req);
706     return 0;
707     }
708    
709     /* Percent-decode request */
710     if (unescape_uri(req->request_uri, &(req->query_string)) == 0) {
711     log_error_doc(req);
712     fputs("Problem unescaping uri\n", stderr);
713     send_r_bad_request(req);
714     return 0;
715     }
716    
717     /* clean pathname */
718     clean_pathname(req->request_uri);
719    
720     if (req->request_uri[0] != '/') {
721     send_r_bad_request(req);
722     return 0;
723     }
724    
725     if (translate_uri(req) == 0) { /* unescape, parse uri */
726     SQUASH_KA(req);
727     return 0; /* failure, close down */
728     }
729    
730     if (req->method == M_POST) {
731     req->post_data_fd = create_temporary_file(1, NULL, 0);
732     if (req->post_data_fd == 0)
733     return(0);
734     return(1); /* success */
735     }
736    
737     if (req->is_cgi) {
738     return init_cgi(req);
739     }
740    
741     req->status = WRITE;
742     return init_get(params, req); /* get and head */
743     }
744    
745 nmav 1.4 /* Parses HTTP/1.1 range values.
746     */
747     static int parse_range( const char* value, unsigned long *p1, unsigned long *p2)
748     {
749     int ret;
750     int len;
751    
752     *p1 = *p2 = 0;
753    
754     len = strlen( value);
755     if (len < 7) return -1;
756    
757     /* we do not accept ranges of the form 10-20,21-30
758     */
759     if (strchr( value, ',') != NULL) return -1;
760    
761     if ( memcmp("bytes=", value, 6) != 0) {
762     return -1;
763     } else value += 6;
764    
765     if (strchr( value, '-') == NULL) return -1;
766    
767     if (value[0] == '-')
768     ret = sscanf( value, "-%lu", p2);
769     else
770     ret = sscanf( value, "%lu-%lu", p1, p2);
771    
772     if (ret == 1) {
773     /* This one accepts ranges of both "-stop" and "start-"
774     */
775     return 0;
776     }
777    
778     if (ret == 2)
779     return 0;
780    
781     return -1;
782     }
783    
784    
785 nmav 1.1 /*
786     * Name: process_option_line
787     *
788     * Description: Parses the contents of req->header_line and takes
789     * appropriate action.
790     */
791    
792     int process_option_line(request * req)
793     {
794     char c, *value, *line = req->header_line;
795    
796     /* Start by aggressively hacking the in-place copy of the header line */
797    
798     #ifdef FASCIST_LOGGING
799     log_error_time();
800     fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
801     #endif
802    
803     value = strchr(line, ':');
804     if (value == NULL)
805     return 0;
806     *value++ = '\0'; /* overwrite the : */
807     to_upper(line); /* header types are case-insensitive */
808     while ((c = *value) && (c == ' ' || c == '\t'))
809     value++;
810    
811     if (!memcmp(line, "IF_MODIFIED_SINCE", 18) && !req->if_modified_since)
812     req->if_modified_since = value;
813    
814     else if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
815     req->content_type = value;
816    
817     else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
818     req->content_length = value;
819    
820     else if (!memcmp(line, "CONNECTION", 11) &&
821     ka_max && req->keepalive != KA_STOPPED) {
822     req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
823     KA_ACTIVE : KA_STOPPED);
824     }
825     /* #ifdef ACCEPT_ON */
826     else if (!memcmp(line, "ACCEPT", 7))
827     add_accept_header(req, value);
828     /* #endif */
829    
830     /* Need agent and referer for logs */
831     else if (!memcmp(line, "REFERER", 8)) {
832     req->header_referer = value;
833     if (!add_cgi_env(req, "REFERER", value, 1))
834     return 0;
835     } else if (!memcmp(line, "USER_AGENT", 11)) {
836     req->header_user_agent = value;
837     if (!add_cgi_env(req, "USER_AGENT", value, 1))
838 nmav 1.4 return 0;
839     } else if (!memcmp(line, "RANGE", 5)) {
840     unsigned long int p1, p2;
841     if (parse_range( value, &p1, &p2) == 0) {
842     req->range_start = p1;
843     req->range_stop = p2;
844     } else {
845     req->range_start = 0;
846     req->range_stop = 0;
847     log_error_time();
848     fprintf(stderr, "bogus range: \"%s\"\n", value);
849     send_r_bad_request(req);
850     }
851     if (!add_cgi_env(req, "RANGE", value, 1))
852 nmav 1.1 return 0;
853 nmav 1.6 } else if (!memcmp(line, "HOST", 4)) {
854     virthost* vhost;
855    
856     while( (*value) == ' ') value++;
857    
858     vhost = find_virthost( value, 0);
859     if (vhost) fprintf(stderr, "Found Host: %s\n", vhost->host);
860     if (vhost) fprintf(stderr, "Found Host: %s\n", vhost->ip);
861     if (vhost) fprintf(stderr, "Found Host: %s\n", vhost->user_dir);
862    
863     if ( vhost && ( vhost->ip == NULL || !memcmp( vhost->ip, req->local_ip_addr, vhost->ip_len) ))
864     {
865     if (req->document_root) free( req->document_root);
866     req->document_root = strdup( vhost->document_root);
867    
868     if (req->user_dir)
869     req->user_dir = strdup( vhost->user_dir);
870     else req->user_dir = NULL;
871     } else { /* No virtual host found. use defaults */
872     if ( default_document_root)
873     req->document_root = strdup( default_document_root);
874     else req->document_root = NULL;
875    
876     req->user_dir = NULL;
877     }
878 nmav 1.1 } 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