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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.23 - (hide annotations)
Wed Oct 2 20:07:26 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.22: +2 -3 lines
File MIME type: text/plain
*** empty log message ***

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26