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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (hide annotations)
Wed Oct 2 08:54:09 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.19: +12 -2 lines
File MIME type: text/plain
Several changes to allow setting the correct query string in HIC cgis.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26