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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.12 - (hide annotations)
Fri Sep 27 21:09:11 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.11: +2 -3 lines
File MIME type: text/plain
Added some preliminary support for fast CGI support (Hydra Internally handled CGI) or HIC. Currently it can be used with php.

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.12 /* $Id: request.c,v 1.11 2002/09/27 12:59:16 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     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 nmav 1.8 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 nmav 1.4
820 nmav 1.1 /*
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 nmav 1.4 return 0;
874     } else if (!memcmp(line, "RANGE", 5)) {
875 nmav 1.8 init_range_stuff( req, value);
876 nmav 1.6 } else if (!memcmp(line, "HOST", 4)) {
877 nmav 1.8 init_vhost_stuff( req, value);
878 nmav 1.10 if (!add_cgi_env(req, "HOST", value, 1))
879     return 0;
880 nmav 1.1 } else {
881     if (!add_cgi_env(req, line, value, 1))
882     return 0;
883     }
884     return 1;
885     }
886    
887     /*
888     * Name: add_accept_header
889     * Description: Adds a mime_type to a requests accept char buffer
890     * silently ignore any that don't fit -
891     * shouldn't happen because of relative buffer sizes
892     */
893    
894     void add_accept_header(request * req, char *mime_type)
895     {
896     #ifdef ACCEPT_ON
897     int l = strlen(req->accept);
898     int l2 = strlen(mime_type);
899    
900     if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
901     return;
902    
903     if (req->accept[0] == '\0')
904     strcpy(req->accept, mime_type);
905     else {
906     req->accept[l] = ',';
907     req->accept[l + 1] = ' ';
908     memcpy(req->accept + l + 2, mime_type, l2 + 1);
909     /* the +1 is for the '\0' */
910     /*
911     sprintf(req->accept + l, ", %s", mime_type);
912     */
913     }
914     #endif
915     }
916    
917     void free_requests(server_params* params)
918     {
919     request *ptr, *next;
920    
921     ptr = params->request_free;
922     while (ptr != NULL) {
923     next = ptr->next;
924     free(ptr);
925     ptr = next;
926     }
927     params->request_free = NULL;
928     }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26