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

Annotation of /hydra/src/request.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.33 - (hide annotations)
Wed Jan 22 07:51:50 2003 UTC (21 years, 2 months ago) by nmav
Branch: MAIN
Changes since 1.32: +880 -813 lines
File MIME type: text/plain
merged changes from 0.1.x branch.

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.33 /* $Id: request.c,v 1.32.2.17 2003/01/19 17:39:10 nmav Exp $*/
25 nmav 1.1
26     #include "boa.h"
27 nmav 1.33 #include <stddef.h> /* for offsetof */
28 nmav 1.1 #include "ssl.h"
29     #include "socket.h"
30    
31     extern int boa_ssl;
32 nmav 1.33 int system_bufsize = 0; /* Default size of SNDBUF given by system */
33 nmav 1.1
34 nmav 1.33 inline static void init_vhost_stuff(request * req, char *value);
35 nmav 1.32
36 nmav 1.1 /* function prototypes located in this file only */
37 nmav 1.33 static void free_request(server_params * params, request ** list_head_addr,
38     request * req);
39 nmav 1.1
40     /*
41     * Name: new_request
42     * Description: Obtains a request struct off the free list, or if the
43     * free list is empty, allocates memory
44     *
45     * Return value: pointer to initialized request
46     */
47    
48 nmav 1.33 request *new_request(server_params * params)
49 nmav 1.1 {
50 nmav 1.33 request *req;
51 nmav 1.1
52 nmav 1.33 if (params->request_free) {
53     req = params->request_free; /* first on free list */
54     dequeue(&params->request_free, params->request_free); /* dequeue the head */
55     } else {
56     req = (request *) malloc(sizeof(request));
57     if (!req) {
58     log_error_time();
59     perror("malloc for new request");
60     return NULL;
61     }
62     }
63     memset(req, 0, offsetof(request, buffer) + 1);
64     req->data_fd = -1;
65     req->post_data_fd.fds[0] = req->post_data_fd.fds[1] = -1;
66 nmav 1.1
67 nmav 1.33 return req;
68 nmav 1.1 }
69    
70     #ifdef ENABLE_SMP
71 nmav 1.33 static pthread_mutex_t accept_mutex[2] = {
72     PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER
73     };
74 nmav 1.1 #endif
75    
76 nmav 1.33 /* Keep 2 numbers. One for the plain connections, and one
77     * for the secure ones (SSL).
78     */
79     static long int total_global_connections[2] = { 0, 0 };
80 nmav 1.25
81     /* Decreases total_global_connections, but does some locking
82     * too.
83     */
84 nmav 1.33 inline static void decrease_global_total_connections(int ssl)
85     {
86     /* if we do want to serve as much as possible, then
87     * don't bother counting connections.
88     */
89     if (max_connections == INT_MAX && max_ssl_connections == INT_MAX)
90     return;
91    
92     #ifdef ENABLE_SMP
93     pthread_mutex_lock(&accept_mutex[ssl]);
94     #endif
95     total_global_connections[ssl]--;
96     #ifdef ENABLE_SMP
97     pthread_mutex_unlock(&accept_mutex[ssl]);
98     #endif
99    
100     }
101    
102     /* Returns the number of total connections
103     */
104     long int get_total_global_connections(int ssl)
105 nmav 1.25 {
106 nmav 1.33 long int ret;
107 nmav 1.25
108     #ifdef ENABLE_SMP
109 nmav 1.33 pthread_mutex_lock(&accept_mutex[ssl]);
110 nmav 1.25 #endif
111 nmav 1.33 ret = total_global_connections[ssl];
112 nmav 1.25 #ifdef ENABLE_SMP
113 nmav 1.33 pthread_mutex_unlock(&accept_mutex[ssl]);
114 nmav 1.25 #endif
115 nmav 1.33 return ret;
116 nmav 1.25
117     }
118    
119 nmav 1.1 /*
120     * Name: get_request
121     *
122     * Description: Polls the server socket for a request. If one exists,
123     * does some basic initialization and adds it to the ready queue;.
124     */
125    
126 nmav 1.33 void get_request(server_params * params, socket_type * server_s)
127 nmav 1.1 {
128 nmav 1.33 int fd; /* socket */
129     struct SOCKADDR remote_addr; /* address */
130     struct SOCKADDR salocal;
131     int remote_addrlen = sizeof(struct SOCKADDR);
132     request *conn; /* connection */
133     int len;
134     static int sockbufsize = SOCKETBUF_SIZE;
135 nmav 1.14 #ifdef ENABLE_SSL
136 nmav 1.33 gnutls_session ssl_state = NULL;
137 nmav 1.14 #endif
138 nmav 1.1
139 nmav 1.33 remote_addr.S_FAMILY = 0xdead;
140    
141 nmav 1.1 #ifdef ENABLE_SMP
142 nmav 1.33 /* We make use of the fact that server_s->secure is either
143     * 0 or 1. 0 Is used for the non SSL mutex, and 1 for the
144     * secure one.
145     */
146     pthread_mutex_lock(&accept_mutex[server_s->secure]);
147     #endif
148    
149     /* If we have reached our max connections limit
150     */
151     if ((!server_s->secure && total_global_connections[0] >= max_connections) ||
152     (server_s->secure && total_global_connections[1] >= max_ssl_connections))
153     {
154     server_s->pending_requests = 0;
155     goto unlock;
156     }
157    
158     fd = accept(server_s->socket, (struct sockaddr *) &remote_addr,
159     &remote_addrlen);
160    
161     if (fd == -1) {
162     if (errno != EAGAIN && errno != EWOULDBLOCK)
163     /* abnormal error */
164     WARN("accept");
165     else
166     /* no requests */
167     server_s->pending_requests = 0;
168     goto unlock;
169     }
170    
171     /* only count, if we have enabled a connection limit */
172     if (max_connections != INT_MAX || max_ssl_connections != INT_MAX) {
173     total_global_connections[server_s->secure]++;
174     }
175 nmav 1.25
176     #ifdef ENABLE_SMP
177 nmav 1.33 /* No dead lock conditions here, since accept() is non blocking.
178     */
179     pthread_mutex_unlock(&accept_mutex[server_s->secure]);
180 nmav 1.1 #endif
181    
182 nmav 1.33 if (fd >= FD_SETSIZE) {
183     WARN("Got fd >= FD_SETSIZE.");
184     close(fd);
185     return;
186     }
187    
188 nmav 1.1 #ifdef ENABLE_SSL
189 nmav 1.33 if (server_s->secure) {
190     ssl_state = initialize_ssl_session();
191     if (ssl_state == NULL) {
192     WARN("Could not initialize SSL session.");
193     close(fd);
194     return;
195     }
196    
197     gnutls_transport_set_ptr(ssl_state, fd);
198     }
199     #endif
200    
201     len = sizeof(salocal);
202    
203     if (getsockname(fd, (struct sockaddr *) &salocal, &len) != 0) {
204     WARN("getsockname");
205     close(fd);
206     return;
207     }
208    
209     conn = new_request(params);
210     if (!conn) {
211     close(fd);
212     return;
213     }
214    
215     conn->fd = fd;
216 nmav 1.14 #ifdef ENABLE_SSL
217 nmav 1.33 conn->ssl_state = ssl_state;
218 nmav 1.14 #endif
219 nmav 1.1
220 nmav 1.33 if (server_s->secure != 0)
221     conn->secure = 1;
222     else
223     conn->secure = 0;
224    
225     if (server_s->secure != 0)
226     conn->status = FINISH_HANDSHAKE;
227     else
228     conn->status = READ_HEADER;
229    
230     conn->header_line = conn->client_stream;
231     conn->time_last = current_time;
232     conn->kacount = ka_max;
233    
234     ascii_sockaddr(&salocal, conn->local_ip_addr, NI_MAXHOST);
235    
236     /* nonblocking socket */
237     if (set_nonblock_fd(conn->fd) == -1)
238     WARN("fcntl: unable to set new socket to non-block");
239    
240     /* set close on exec to true */
241     if (set_cloexec_fd(conn->fd) == -1)
242     WARN("fctnl: unable to set close-on-exec for new socket");
243    
244     /* Increase buffer size if we have to.
245     * Only ask the system the buffer size on the first request,
246     * and assume all subsequent sockets have the same size.
247     */
248     if (system_bufsize == 0) {
249     len = sizeof(system_bufsize);
250     if (getsockopt
251     (conn->fd, SOL_SOCKET, SO_SNDBUF, &system_bufsize, &len) == 0
252     && len == sizeof(system_bufsize)) {
253     ;
254     } else {
255     WARN("getsockopt(SNDBUF)");
256     system_bufsize = sockbufsize;
257     }
258     }
259     if (system_bufsize < params->sockbufsize) {
260     if (setsockopt
261     (conn->fd, SOL_SOCKET, SO_SNDBUF, (void *) &params->sockbufsize,
262     sizeof(params->sockbufsize)) == -1) {
263     WARN("setsockopt: unable to set socket buffer size");
264 nmav 1.1 #ifdef DIE_ON_ERROR_TUNING_SNDBUF
265 nmav 1.33 exit(errno);
266 nmav 1.1 #endif
267 nmav 1.33 }
268     }
269    
270     init_vhost_stuff(conn, "");
271    
272     /* for log file and possible use by CGI programs */
273     ascii_sockaddr(&remote_addr, conn->remote_ip_addr, NI_MAXHOST);
274 nmav 1.1
275 nmav 1.33 /* for possible use by CGI programs */
276     conn->remote_port = net_port(&remote_addr);
277 nmav 1.1
278 nmav 1.33 params->status.requests++;
279 nmav 1.1
280 nmav 1.33 socket_set_options(conn->fd);
281 nmav 1.1
282 nmav 1.33 params->total_connections++;
283 nmav 1.5
284 nmav 1.33 enqueue(&params->request_ready, conn);
285    
286     return;
287 nmav 1.25
288 nmav 1.33 unlock:
289 nmav 1.25 #ifdef ENABLE_SMP
290 nmav 1.33 pthread_mutex_unlock(&accept_mutex[server_s->secure]);
291 nmav 1.25 #endif
292     return;
293 nmav 1.1 }
294    
295    
296     /*
297     * Name: free_request
298     *
299     * Description: Deallocates memory for a finished request and closes
300     * down socket.
301     */
302    
303 nmav 1.33 static void free_request(server_params * params, request ** list_head_addr,
304     request * req)
305 nmav 1.1 {
306 nmav 1.33 int i;
307     /* free_request should *never* get called by anything but
308     process_requests */
309    
310     if (req->buffer_end && req->status != DEAD) {
311     req->status = DONE;
312     return;
313     }
314     /* put request on the free list */
315     dequeue(list_head_addr, req); /* dequeue from ready or block list */
316    
317     if (req->logline) /* access log */
318     log_access(req);
319    
320     if (req->mmap_entry_var)
321     release_mmap(req->mmap_entry_var);
322     /* FIXME: Why is it needed? */
323     else if (req->data_mem)
324     munmap(req->data_mem, req->filesize);
325    
326     if (req->data_fd != -1)
327     close(req->data_fd);
328    
329     close_tmp_fd(&req->post_data_fd);
330    
331     if (req->response_status >= 400)
332     params->status.errors++;
333    
334     for (i = COMMON_CGI_COUNT; i < req->cgi_env_index; ++i) {
335     if (req->cgi_env[i]) {
336     free(req->cgi_env[i]);
337     } else {
338     log_error_time();
339     fprintf(stderr, "Warning: CGI Environment contains NULL value"
340     "(index %d of %d).\n", i, req->cgi_env_index);
341     }
342     }
343    
344     free(req->pathname);
345     free(req->query_string);
346     free(req->path_info);
347     free(req->path_translated);
348     free(req->script_name);
349    
350     if ((req->keepalive == KA_ACTIVE) &&
351     (req->response_status < 500) && req->kacount > 0) {
352     int bytes_to_move;
353    
354     request *conn = new_request(params);
355     if (!conn) {
356     /* errors already reported */
357     enqueue(&params->request_free, req);
358     close(req->fd);
359     params->total_connections--;
360     decrease_global_total_connections(req->secure);
361     return;
362     }
363     conn->fd = req->fd;
364 nmav 1.1
365     #ifdef ENABLE_SSL
366 nmav 1.33 if (req->secure != 0) {
367     conn->secure = 1;
368     conn->ssl_state = req->ssl_state;
369    
370     conn->status = READ_HEADER;
371     } else {
372 nmav 1.1 #endif
373 nmav 1.33 conn->secure = 0;
374     conn->status = READ_HEADER;
375 nmav 1.1 #ifdef ENABLE_SSL
376 nmav 1.33 conn->ssl_state = NULL;
377     }
378 nmav 1.1 #endif
379    
380 nmav 1.33 conn->header_line = conn->client_stream;
381     conn->kacount = req->kacount - 1;
382    
383     /* close enough and we avoid a call to time(NULL) */
384     conn->time_last = req->time_last;
385    
386     /* for log file and possible use by CGI programs */
387     memcpy(conn->remote_ip_addr, req->remote_ip_addr, NI_MAXHOST);
388     memcpy(conn->local_ip_addr, req->local_ip_addr, NI_MAXHOST);
389    
390     /* for possible use by CGI programs */
391     conn->remote_port = req->remote_port;
392    
393     conn->action = req->action;
394    
395     params->status.requests++;
396    
397     /* we haven't parsed beyond req->parse_pos, so... */
398     bytes_to_move = req->client_stream_pos - req->parse_pos;
399    
400     if (bytes_to_move) {
401     memcpy(conn->client_stream,
402     req->client_stream + req->parse_pos, bytes_to_move);
403     conn->client_stream_pos = bytes_to_move;
404     }
405     enqueue(&params->request_block, conn);
406    
407     BOA_FD_SET(conn, conn->fd, BOA_READ);
408    
409     enqueue(&params->request_free, req);
410    
411     return;
412     }
413    
414     /*
415     While debugging some weird errors, Jon Nelson learned that
416     some versions of Netscape Navigator break the
417     HTTP specification.
418    
419     Some research on the issue brought up:
420    
421     http://www.apache.org/docs/misc/known_client_problems.html
422    
423     As quoted here:
424 nmav 1.1
425 nmav 1.33 "
426     Trailing CRLF on POSTs
427 nmav 1.1
428 nmav 1.33 This is a legacy issue. The CERN webserver required POST
429     data to have an extra CRLF following it. Thus many
430     clients send an extra CRLF that is not included in the
431     Content-Length of the request. Apache works around this
432     problem by eating any empty lines which appear before a
433     request.
434     "
435    
436     Boa will (for now) hack around this stupid bug in Netscape
437     (and Internet Exploder)
438     by reading up to 32k after the connection is all but closed.
439     This should eliminate any remaining spurious crlf sent
440     by the client.
441    
442     Building bugs *into* software to be compatable is
443     just plain wrong
444     */
445    
446     if (req->method == M_POST) {
447     char buf[32768];
448    
449     socket_recv(req, buf, sizeof(buf));
450     }
451 nmav 1.1 #ifdef ENABLE_SSL
452 nmav 1.33 if (req->secure) {
453     gnutls_bye(req->ssl_state, GNUTLS_SHUT_WR);
454     gnutls_deinit(req->ssl_state);
455     }
456 nmav 1.1 #endif
457 nmav 1.33 close(req->fd);
458 nmav 1.1
459 nmav 1.33 params->total_connections--;
460     decrease_global_total_connections(req->secure);
461 nmav 1.1
462 nmav 1.33 enqueue(&params->request_free, req);
463 nmav 1.1
464 nmav 1.33 return;
465 nmav 1.1 }
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.33 void process_requests(server_params * params, socket_type * server_s)
478 nmav 1.1 {
479 nmav 1.33 int retval = 0;
480     request *current, *trailer;
481 nmav 1.1
482 nmav 1.33 if (server_s->pending_requests) {
483     get_request(params, server_s);
484 nmav 1.1 #ifdef ORIGINAL_BEHAVIOR
485 nmav 1.33 server_s->pending_requests = 0;
486 nmav 1.1 #endif
487 nmav 1.33 }
488 nmav 1.1
489 nmav 1.33 current = params->request_ready;
490 nmav 1.1
491 nmav 1.33 while (current) {
492     if (current->buffer_end && /* there is data in the buffer */
493     current->status != DEAD && current->status != DONE) {
494     retval = req_flush(current);
495     /*
496     * retval can be -2=error, -1=blocked, or bytes left
497     */
498     if (retval == -2) { /* error */
499     current->status = DEAD;
500     retval = 0;
501     } else if (retval >= 0) {
502     /* notice the >= which is different from below?
503     Here, we may just be flushing headers.
504     We don't want to return 0 because we are not DONE
505     or DEAD */
506    
507     retval = 1;
508     }
509     } else {
510     switch (current->status) {
511 nmav 1.1 #ifdef ENABLE_SSL
512 nmav 1.33 case FINISH_HANDSHAKE:
513     retval = finish_handshake(current);
514     break;
515     case SEND_ALERT:
516     retval = send_alert(current);
517     break;
518     #endif
519     case READ_HEADER:
520     case ONE_CR:
521     case ONE_LF:
522     case TWO_CR:
523     retval = read_header(params, current);
524     break;
525     case BODY_READ:
526     retval = read_body(current);
527     break;
528     case BODY_WRITE:
529     retval = write_body(current);
530     break;
531     case WRITE:
532     retval = process_get(params, current);
533     break;
534     case PIPE_READ:
535     retval = read_from_pipe(current);
536     break;
537     case PIPE_WRITE:
538     retval = write_from_pipe(current);
539     break;
540     case IOSHUFFLE:
541     retval = io_shuffle(current);
542     break;
543     case DONE:
544     /* a non-status that will terminate the request */
545     retval = req_flush(current);
546     /*
547     * retval can be -2=error, -1=blocked, or bytes left
548     */
549     if (retval == -2) { /* error */
550     current->status = DEAD;
551     retval = 0;
552     } else if (retval > 0) {
553     retval = 1;
554     }
555     break;
556     case DEAD:
557     retval = 0;
558     current->buffer_end = 0;
559     SQUASH_KA(current);
560     break;
561     default:
562     retval = 0;
563     fprintf(stderr, "Unknown status (%d), "
564     "closing!\n", current->status);
565     current->status = DEAD;
566     break;
567     }
568    
569     }
570    
571     if (params->sigterm_flag)
572     SQUASH_KA(current);
573    
574     /* we put this here instead of after the switch so that
575     * if we are on the last request, and get_request is successful,
576     * current->next is valid!
577     */
578     if (server_s->pending_requests)
579     get_request(params, server_s);
580    
581     switch (retval) {
582     case -1: /* request blocked */
583     trailer = current;
584     current = current->next;
585     block_request(params, trailer);
586     break;
587     case 0: /* request complete */
588     current->time_last = current_time;
589     trailer = current;
590     current = current->next;
591     free_request(params, &params->request_ready, trailer);
592     break;
593     case 1: /* more to do */
594     current->time_last = current_time;
595     current = current->next;
596     break;
597     default:
598     log_error_time();
599     fprintf(stderr, "Unknown retval in process.c - "
600     "Status: %d, retval: %d\n", current->status, retval);
601     current = current->next;
602     break;
603     }
604     }
605     }
606    
607     /* Initializes several stuff that depend on the sent HTTP
608     * version number.
609     *
610     * Returns true on sucess, or 0 otherwise.
611     */
612     inline static
613     int init_http_version_specific_stuff(request * req)
614     {
615     if ( req->http_version==HTTP_1_1) {
616     if (!req->keepalive_given)
617     req->keepalive = KA_ACTIVE; /* keepalive is active by default */
618    
619     if (req->hostname_given == 0) {
620     return 0;
621     }
622     }
623    
624     return 1; /* success */
625 nmav 1.1 }
626    
627     /*
628     * Name: process_logline
629     *
630     * Description: This is called with the first req->header_line received
631     * by a request, called "logline" because it is logged to a file.
632     * It is parsed to determine request type and method, then passed to
633     * translate_uri for further parsing. Also sets up CGI environment if
634     * needed.
635     */
636 nmav 1.2 #define SIMPLE_HTTP_VERSION "HTTP/0.9"
637 nmav 1.1 int process_logline(request * req)
638     {
639 nmav 1.33 char *stop, *stop2;
640 nmav 1.1
641 nmav 1.33 req->logline = req->client_stream;
642     if (!memcmp(req->logline, "GET ", 4))
643     req->method = M_GET;
644     else if (!memcmp(req->logline, "HEAD ", 5))
645     /* head is just get w/no body */
646     req->method = M_HEAD;
647     else if (!memcmp(req->logline, "POST ", 5))
648     req->method = M_POST;
649     else {
650     log_error_doc(req);
651     fprintf(stderr, "malformed request: \"%s\"\n", req->logline);
652     send_r_not_implemented(req);
653     return 0;
654     }
655    
656     req->http_version_str = SIMPLE_HTTP_VERSION;
657     req->http_version = HTTP_0_9;
658    
659     /* Guaranteed to find ' ' since we matched a method above */
660     stop = req->logline + 3;
661     if (*stop != ' ')
662     ++stop;
663    
664     /* scan to start of non-whitespace */
665     while (*(++stop) == ' ');
666    
667     stop2 = stop;
668    
669     /* scan to end of non-whitespace */
670     while (*stop2 != '\0' && *stop2 != ' ')
671     ++stop2;
672    
673     if (stop2 - stop > MAX_HEADER_LENGTH) {
674     log_error_doc(req);
675     fprintf(stderr, "URI too long %d: \"%s\"\n", MAX_HEADER_LENGTH,
676     req->logline);
677     send_r_bad_request(req);
678     return 0;
679     }
680     memcpy(req->request_uri, stop, stop2 - stop);
681     req->request_uri[stop2 - stop] = '\0';
682    
683     if (*stop2 == ' ') {
684     /* if found, we should get an HTTP/x.x */
685     unsigned int p1, p2;
686    
687     /* scan to end of whitespace */
688     ++stop2;
689     while (*stop2 == ' ' && *stop2 != '\0')
690     ++stop2;
691    
692     /* scan in HTTP/major.minor */
693     if (sscanf(stop2, "HTTP/%u.%u", &p1, &p2) == 2) {
694     /* HTTP/{0.9,1.0,1.1} */
695     if (p1 == 1) { /* We accept all HTTP/1.x versions */
696     req->http_version_str = stop2;
697     switch(p2) {
698     case 0:
699     req->http_version = HTTP_1_0;
700     break;
701     case 1:
702     default:
703     req->http_version = HTTP_1_1;
704     }
705     } else if (p1 > 1) { /* major number > 1 is invalid for us */
706     goto BAD_VERSION;
707     }
708     } else {
709     goto BAD_VERSION;
710     }
711    
712     }
713    
714     if (req->method == M_HEAD && req->http_version == HTTP_0_9) {
715     send_r_bad_request(req);
716     return 0;
717     }
718     req->cgi_env_index = COMMON_CGI_COUNT;
719    
720     return 1;
721    
722     BAD_VERSION:
723     log_error_doc(req);
724     fprintf(stderr, "bogus HTTP version: \"%s\"\n", stop2);
725     send_r_bad_request(req);
726     return 0;
727 nmav 1.1 }
728    
729     /*
730     * Name: process_header_end
731     *
732     * Description: takes a request and performs some final checking before
733     * init_cgi or init_get
734     * Returns 0 for error or NPH, or 1 for success
735     */
736    
737 nmav 1.33 int process_header_end(server_params * params, request * req)
738 nmav 1.1 {
739 nmav 1.33 char *p = NULL;
740 nmav 1.20
741 nmav 1.33 if (!req->logline) {
742     send_r_error(req);
743     return 0;
744     }
745    
746     /* Check if all the stuff matches the HTTP version
747     * sent.
748     */
749     if (!init_http_version_specific_stuff(req)) {
750     send_r_bad_request(req);
751     return 0;
752     }
753    
754     /* Percent-decode request */
755     if (unescape_uri(req->request_uri, &p) == 0) {
756     log_error_doc(req);
757     fputs("Problem unescaping uri\n", stderr);
758     send_r_bad_request(req);
759     return 0;
760     }
761    
762     if (p) {
763     req->query_string = strdup(p);
764     if (req->query_string == NULL) {
765     send_r_error(req);
766     return 0;
767     }
768     }
769    
770     /* clean pathname */
771     clean_pathname(req->request_uri);
772    
773     if (req->request_uri[0] != '/') {
774     send_r_bad_request(req);
775     return 0;
776     }
777    
778     if (translate_uri(req) == 0) { /* unescape, parse uri */
779     SQUASH_KA(req);
780     return 0; /* failure, close down */
781     }
782    
783     if (req->method == M_POST) {
784     req->post_data_fd =
785     create_temporary_file(1, boa_atoi(req->content_length));
786     if (req->post_data_fd.fds[0] == -1)
787     return (0);
788    
789     if (req->post_data_fd.pipe == 0) {
790     if (set_cloexec_fd(req->post_data_fd.fds[0]) == -1) {
791     WARN("unable to set close-on-exec for req->post_data_fd!");
792     close_tmp_fd(&req->post_data_fd);
793     return (0);
794     }
795     }
796    
797     return (1); /* success */
798     }
799    
800     if (req->is_cgi) {
801     return init_cgi(req);
802     }
803 nmav 1.1
804 nmav 1.33 req->status = WRITE;
805     return init_get(params, req); /* get and head */
806 nmav 1.1 }
807    
808 nmav 1.4 /* Parses HTTP/1.1 range values.
809     */
810 nmav 1.33 static int parse_range(const char *value, large_int * val1,
811     large_int * val2)
812 nmav 1.4 {
813 nmav 1.33 int len;
814     char *p;
815    
816     *val1 = *val2 = 0;
817    
818     len = strlen(value);
819     if (len < 7)
820     return -1;
821    
822     /* we do not accept ranges of the form "bytes=10-20,21-30"
823     */
824     if (strchr(value, ',') != NULL)
825     return -1;
826    
827     if (memcmp("bytes=", value, 6) != 0) {
828     return -1;
829     } else
830     value += 6;
831    
832     while (*value == ' ')
833     value++;
834     if ((p = strchr(value, '-')) == NULL)
835     return -1;
836    
837     if (value[0] == '-') { /* Handle case "bytes=-1024" */
838     *val1 = 0;
839     *val2 = boa_atoll(&value[1]);
840     return 0;
841     } else {
842     char buf[43];
843     int len;
844    
845     /* two values of the form "xxx-yyy" */
846    
847     if ((len = strlen(value)) >= sizeof(buf))
848     return -1;
849 nmav 1.4
850 nmav 1.33 memcpy(buf, value, len);
851     buf[len] = 0;
852 nmav 1.4
853 nmav 1.33 p = strchr(buf, '-');
854     if (p == NULL)
855     return -1;
856     *p = 0;
857     p++;
858 nmav 1.8
859 nmav 1.33 while (*p == ' ')
860     p++;
861    
862     *val1 = boa_atoll(buf);
863    
864     if (*p == '\0') /* form: "xxx-" */
865     *val2 = 0;
866     else
867     *val2 = boa_atoll(p);
868    
869     if (*val1 == -1)
870     return -1;
871    
872     return 0;
873     }
874    
875     return -1;
876     }
877    
878     inline static void init_range_stuff(request * req, char *value)
879     {
880     large_int p1, p2;
881     if (parse_range(value, &p1, &p2) == 0) {
882     req->range_start = p1;
883     req->range_stop = p2;
884     } else {
885     req->range_start = -1;
886     req->range_stop = -1;
887     log_error_doc(req);
888     fprintf(stderr, "bogus range: \"%s\"\n", value);
889    
890     /* here we just ignore a bogus range,
891     * but we have put illegal values in
892     * range start and range stop, to
893     * be detected in init_get().
894     */
895     }
896     }
897    
898     inline static void init_vhost_stuff(request * req, char *value)
899     {
900     virthost *vhost;
901     int valuelen;
902    
903     valuelen = strlen(value);
904    
905     vhost = find_virthost(value, valuelen);
906    
907     if (vhost == NULL && value[0] != 0) {
908     value = "";
909     vhost = find_virthost("", 0);
910     }
911    
912     if (vhost
913     && (vhost->ip == NULL
914     || !memcmp(vhost->ip, req->local_ip_addr, vhost->ip_len))) {
915     req->hostname = value;
916     memcpy(req->document_root, vhost->document_root,
917     vhost->document_root_len + 1);
918     if (vhost->user_dir)
919     memcpy(req->user_dir, vhost->user_dir, vhost->user_dir_len + 1);
920    
921     }
922 nmav 1.29
923 nmav 1.8 }
924 nmav 1.4
925 nmav 1.1 /*
926     * Name: process_option_line
927     *
928     * Description: Parses the contents of req->header_line and takes
929     * appropriate action.
930     */
931    
932     int process_option_line(request * req)
933     {
934 nmav 1.33 char c, *value, *line = req->header_line;
935 nmav 1.1
936 nmav 1.33 /* Start by aggressively hacking the in-place copy of the header line */
937 nmav 1.1
938     #ifdef FASCIST_LOGGING
939 nmav 1.33 log_error_time();
940     fprintf(stderr, "%s:%d - Parsing \"%s\"\n", __FILE__, __LINE__, line);
941 nmav 1.1 #endif
942    
943 nmav 1.33 value = strchr(line, ':');
944     if (value == NULL)
945     return 0;
946     *value++ = '\0'; /* overwrite the : */
947     to_upper(line); /* header types are case-insensitive */
948     while ((c = *value) && (c == ' ' || c == '\t'))
949     value++;
950    
951    
952     switch (line[0]) {
953    
954     case 'A':
955     if (!memcmp(line, "ACCEPT", 7))
956     add_accept_header(req, value);
957     else
958     goto just_add_header;
959     break;
960    
961     case 'C':
962     if (!memcmp(line, "CONTENT_TYPE", 13) && !req->content_type)
963     req->content_type = value;
964     else if (!memcmp(line, "CONTENT_LENGTH", 15) && !req->content_length)
965     req->content_length = value;
966     else if (!memcmp(line, "CONNECTION", 11) &&
967     ka_max && req->keepalive != KA_STOPPED) {
968     req->keepalive_given = 1;
969     req->keepalive = (!strncasecmp(value, "Keep-Alive", 10) ?
970     KA_ACTIVE : KA_STOPPED);
971     } else
972     goto just_add_header;
973    
974     break;
975    
976     case 'H':
977     if (!memcmp(line, "HOST", 4)) {
978     req->hostname_given = 1;
979     init_vhost_stuff(req, value);
980     if (!add_cgi_env(req, "HOST", value, 1))
981     return 0;
982     } else
983     goto just_add_header;
984     break;
985    
986     case 'I':
987     if (!memcmp(line, "IF_", 3)) {
988     char *p = line + 3;
989    
990     if (!memcmp(p, "MODIFIED_SINCE", 15) && !req->if_modified_since) {
991     req->if_types |= IF_MODIFIED_SINCE;
992     req->if_modified_since = value;
993    
994     } else if (!memcmp(p, "MATCH", 5) && !req->if_match_etag) {
995     req->if_types |= IF_MATCH;
996     req->if_match_etag = value;
997    
998     } else if (!memcmp(p, "NONE_MATCH", 10)
999     && !req->if_none_match_etag) {
1000     req->if_types |= IF_NONE_MATCH;
1001     req->if_none_match_etag = value;
1002    
1003     } else if (!memcmp(p, "RANGE", 5) && !req->if_range_etag) {
1004     req->if_types |= IF_RANGE;
1005     req->if_range_etag = value;
1006     }
1007    
1008     if (!add_cgi_env(req, line, value, 1))
1009     return 0;
1010     break;
1011     } else
1012     goto just_add_header;
1013    
1014    
1015     case 'R':
1016     /* Need agent and referer for logs */
1017     if (!memcmp(line, "REFERER", 8)) {
1018     req->header_referer = value;
1019     if (!add_cgi_env(req, "REFERER", value, 1))
1020     return 0;
1021     } else if (!memcmp(line, "RANGE", 5)) {
1022     init_range_stuff(req, value);
1023     } else goto just_add_header;
1024     break;
1025    
1026 nmav 1.16
1027 nmav 1.33 case 'U':
1028     if (!memcmp(line, "USER_AGENT", 11)) {
1029     req->header_user_agent = value;
1030     if (!add_cgi_env(req, "USER_AGENT", value, 1))
1031     return 0;
1032     } else
1033     goto just_add_header;
1034     break;
1035    
1036     default:
1037     just_add_header:
1038     if (!add_cgi_env(req, line, value, 1))
1039     return 0;
1040     break;
1041    
1042     }
1043    
1044     return 1;
1045 nmav 1.27
1046 nmav 1.1 }
1047    
1048     /*
1049     * Name: add_accept_header
1050     * Description: Adds a mime_type to a requests accept char buffer
1051     * silently ignore any that don't fit -
1052     * shouldn't happen because of relative buffer sizes
1053     */
1054    
1055     void add_accept_header(request * req, char *mime_type)
1056     {
1057     #ifdef ACCEPT_ON
1058 nmav 1.33 int l = strlen(req->accept);
1059     int l2 = strlen(mime_type);
1060 nmav 1.1
1061 nmav 1.33 if ((l + l2 + 2) >= MAX_HEADER_LENGTH)
1062     return;
1063 nmav 1.1
1064 nmav 1.33 if (req->accept[0] == '\0')
1065     strcpy(req->accept, mime_type);
1066     else {
1067     req->accept[l] = ',';
1068     req->accept[l + 1] = ' ';
1069     memcpy(req->accept + l + 2, mime_type, l2 + 1);
1070     /* the +1 is for the '\0' */
1071     /*
1072     sprintf(req->accept + l, ", %s", mime_type);
1073     */
1074     }
1075 nmav 1.1 #endif
1076     }
1077    
1078 nmav 1.33 void free_requests(server_params * params)
1079     {
1080     request *ptr, *next;
1081    
1082     ptr = params->request_free;
1083     while (ptr != NULL) {
1084     next = ptr->next;
1085     free(ptr);
1086     ptr = next;
1087     }
1088     params->request_free = NULL;
1089 nmav 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26