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

Annotation of /hydra/src/read.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (hide annotations)
Sat Sep 28 16:32:37 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_3, hydra_0_0_4
Changes since 1.2: +2 -2 lines
File MIME type: text/plain
In sighup and sigterm, the HIC thread is terminated as well.

1 nmav 1.1 /*
2 nmav 1.3 * 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) 1997,99 Jon Nelson <jnelson@boa.org>
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 1, or (at your option)
10     * any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20     *
21     */
22    
23 nmav 1.3 /* $Id: read.c,v 1.2 2002/09/22 15:12:03 nmav Exp $*/
24 nmav 1.1
25     #include "boa.h"
26     #include "socket.h"
27    
28     /*
29     * Name: read_header
30     * Description: Reads data from a request socket. Manages the current
31     * status via a state machine. Changes status from READ_HEADER to
32     * READ_BODY or WRITE as necessary.
33     *
34     * Return values:
35     * -1: request blocked, move to blocked queue
36     * 0: request done, close it down
37     * 1: more to do, leave on ready list
38     */
39    
40     int read_header(server_params * params, request * req)
41     {
42 nmav 1.2 int bytes, buf_bytes_left;
43     char *check, *buffer;
44 nmav 1.1
45 nmav 1.2 check = req->client_stream + req->parse_pos;
46     buffer = req->client_stream;
47     bytes = req->client_stream_pos;
48 nmav 1.1
49     #ifdef VERY_FASCIST_LOGGING
50 nmav 1.2 if (check < (buffer + bytes)) {
51     buffer[bytes] = '\0';
52     log_error_time();
53     fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n",
54     __FILE__, __LINE__, check);
55     }
56 nmav 1.1 #endif
57 nmav 1.2 while (check < (buffer + bytes)) {
58     switch (req->status) {
59     case READ_HEADER:
60     if (*check == '\r') {
61     req->status = ONE_CR;
62     req->header_end = check;
63     } else if (*check == '\n') {
64     req->status = ONE_LF;
65     req->header_end = check;
66     }
67     break;
68    
69     case ONE_CR:
70     if (*check == '\n')
71     req->status = ONE_LF;
72     else if (*check != '\r')
73     req->status = READ_HEADER;
74     break;
75    
76     case ONE_LF:
77     /* if here, we've found the end (for sure) of a header */
78     if (*check == '\r') /* could be end o headers */
79     req->status = TWO_CR;
80     else if (*check == '\n')
81     req->status = BODY_READ;
82     else
83     req->status = READ_HEADER;
84     break;
85    
86     case TWO_CR:
87     if (*check == '\n')
88     req->status = BODY_READ;
89     else if (*check != '\r')
90     req->status = READ_HEADER;
91     break;
92    
93     default:
94     break;
95     }
96 nmav 1.1
97     #ifdef VERY_FASCIST_LOGGING
98 nmav 1.2 log_error_time();
99     fprintf(stderr, "status, check: %d, %d\n", req->status, *check);
100 nmav 1.1 #endif
101    
102 nmav 1.2 req->parse_pos++; /* update parse position */
103     check++;
104 nmav 1.1
105 nmav 1.2 if (req->status == ONE_LF) {
106     *req->header_end = '\0';
107 nmav 1.1
108 nmav 1.2 /* terminate string that begins at req->header_line */
109 nmav 1.1
110 nmav 1.2 if (req->logline) {
111     if (process_option_line(req) == 0) {
112     return 0;
113 nmav 1.1 }
114 nmav 1.2 } else {
115     if (process_logline(req) == 0)
116     return 0;
117     if (req->simple)
118     return process_header_end(params, req);
119     }
120     /* set header_line to point to beginning of new header */
121     req->header_line = check;
122     } else if (req->status == BODY_READ) {
123 nmav 1.1 #ifdef VERY_FASCIST_LOGGING
124 nmav 1.2 int retval;
125     log_error_time();
126     fprintf(stderr, "%s:%d -- got to body read.\n",
127     __FILE__, __LINE__);
128     retval = process_header_end(params, req);
129 nmav 1.1 #else
130 nmav 1.2 int retval = process_header_end(params, req);
131 nmav 1.1 #endif
132 nmav 1.2 /* process_header_end inits non-POST cgi's */
133    
134     if (retval && req->method == M_POST) {
135     /* for body_{read,write}, set header_line to start of data,
136     and header_end to end of data */
137     req->header_line = check;
138     req->header_end = req->client_stream + req->client_stream_pos;
139 nmav 1.1
140 nmav 1.2 req->status = BODY_WRITE;
141     /* so write it */
142     /* have to write first, or read will be confused
143     * because of the special case where the
144     * filesize is less than we have already read.
145     */
146    
147     /*
148    
149     As quoted from RFC1945:
150    
151     A valid Content-Length is required on all HTTP/1.0 POST requests. An
152     HTTP/1.0 server should respond with a 400 (bad request) message if it
153     cannot determine the length of the request message's content.
154    
155     */
156    
157     if (req->content_length) {
158     int content_length;
159    
160     content_length = boa_atoi(req->content_length);
161     /* Is a content-length of 0 legal? */
162     if (content_length <= 0) {
163     log_error_time();
164     fprintf(stderr,
165     "Invalid Content-Length [%s] on POST!\n",
166     req->content_length);
167     send_r_bad_request(req);
168     return 0;
169     }
170     if (single_post_limit && content_length > single_post_limit) {
171     log_error_time();
172     fprintf(stderr,
173     "Content-Length [%d] > SinglePostLimit [%d] on POST!\n",
174     content_length, single_post_limit);
175     send_r_bad_request(req);
176     return 0;
177     }
178     req->filesize = content_length;
179     req->filepos = 0;
180     if (req->header_end - req->header_line > req->filesize) {
181     req->header_end = req->header_line + req->filesize;
182     }
183     } else {
184     log_error_time();
185     fprintf(stderr, "Unknown Content-Length POST!\n");
186     send_r_bad_request(req);
187     return 0;
188     }
189     } /* either process_header_end failed or req->method != POST */
190     return retval; /* 0 - close it done, 1 - keep on ready */
191     } /* req->status == BODY_READ */
192     } /* done processing available buffer */
193 nmav 1.1
194     #ifdef VERY_FASCIST_LOGGING
195 nmav 1.2 log_error_time();
196     fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n",
197     __FILE__, __LINE__, req->status);
198 nmav 1.1 #endif
199    
200 nmav 1.2 if (req->status < BODY_READ) {
201     /* only reached if request is split across more than one packet */
202    
203     buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos;
204     if (buf_bytes_left < 1) {
205     log_error_time();
206     fputs("buffer overrun - read.c, read_header - closing\n", stderr);
207     req->status = DEAD;
208     return 0;
209     }
210    
211     bytes =
212     socket_recv(req, buffer + req->client_stream_pos,
213     buf_bytes_left);
214 nmav 1.1
215 nmav 1.2 if (bytes < 0) {
216     if (bytes == BOA_E_INTR)
217     return 1;
218     if (bytes == BOA_E_AGAIN)
219     return -1;
220    
221     log_error_doc(req);
222     perror("header read"); /* don't need to save errno because log_error_doc does */
223     return 0;
224     } else if (bytes == 0) {
225     /* this is an error. premature end of headers! */
226     return 0;
227     }
228 nmav 1.1
229 nmav 1.2 /* bytes is positive */
230     req->client_stream_pos += bytes;
231 nmav 1.1
232     #ifdef FASCIST_LOGGING1
233 nmav 1.2 log_error_time();
234     req->client_stream[req->client_stream_pos] = '\0';
235     fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n",
236     __FILE__, __LINE__, bytes,
237 nmav 1.1 #ifdef VERY_FASCIST_LOGGING2
238 nmav 1.2 req->client_stream + req->client_stream_pos - bytes);
239 nmav 1.1 #else
240 nmav 1.2 "");
241 nmav 1.1 #endif
242     #endif
243    
244 nmav 1.2 return 1;
245     }
246     return 1;
247 nmav 1.1 }
248    
249     /*
250     * Name: read_body
251     * Description: Reads body from a request socket for POST CGI
252     *
253     * Return values:
254     *
255     * -1: request blocked, move to blocked queue
256     * 0: request done, close it down
257     * 1: more to do, leave on ready list
258     *
259    
260     As quoted from RFC1945:
261    
262     A valid Content-Length is required on all HTTP/1.0 POST requests. An
263     HTTP/1.0 server should respond with a 400 (bad request) message if it
264     cannot determine the length of the request message's content.
265    
266     */
267    
268     int read_body(request * req)
269     {
270 nmav 1.2 int bytes_read, bytes_to_read, bytes_free;
271 nmav 1.1
272 nmav 1.2 bytes_free = BUFFER_SIZE - (req->header_end - req->header_line);
273     bytes_to_read = req->filesize - req->filepos;
274 nmav 1.1
275 nmav 1.2 if (bytes_to_read > bytes_free)
276     bytes_to_read = bytes_free;
277 nmav 1.1
278 nmav 1.2 if (bytes_to_read <= 0) {
279     req->status = BODY_WRITE; /* go write it */
280     return 1;
281     }
282    
283     bytes_read = socket_recv(req, req->header_end, bytes_to_read);
284    
285     if (bytes_read < 0) {
286     if (bytes_read == BOA_E_AGAIN) {
287     return -1;
288     } else {
289     boa_perror(req, "read body");
290     return 0;
291     }
292    
293     } else if (bytes_read == 0) {
294     /* this is an error. premature end of body! */
295     log_error_time();
296     fprintf(stderr, "%s:%d - Premature end of body!!\n",
297     __FILE__, __LINE__);
298     send_r_bad_request(req);
299     return 0;
300     }
301 nmav 1.1
302 nmav 1.2 req->status = BODY_WRITE;
303 nmav 1.1
304     #ifdef FASCIST_LOGGING1
305 nmav 1.2 log_error_time();
306     fprintf(stderr, "%s:%d - read %d bytes.\n",
307     __FILE__, __LINE__, bytes_to_read);
308 nmav 1.1 #endif
309    
310 nmav 1.2 req->header_end += bytes_read;
311 nmav 1.1
312 nmav 1.2 return 1;
313 nmav 1.1 }
314    
315     /*
316     * Name: write_body
317     * Description: Writes a chunk of data to a file
318     *
319     * Return values:
320     * -1: request blocked, move to blocked queue
321     * 0: EOF or error, close it down
322     * 1: successful write, recycle in ready queue
323     */
324    
325     int write_body(request * req)
326     {
327 nmav 1.2 int bytes_written, bytes_to_write = req->header_end - req->header_line;
328     if (req->filepos + bytes_to_write > req->filesize)
329     bytes_to_write = req->filesize - req->filepos;
330    
331     if (bytes_to_write == 0) { /* nothing left in buffer to write */
332     req->header_line = req->header_end = req->buffer;
333     if (req->filepos >= req->filesize)
334     return init_cgi(req);
335     /* if here, we can safely assume that there is more to read */
336     req->status = BODY_READ;
337     return 1;
338     }
339    
340     bytes_written =
341     write(req->post_data_fd, req->header_line, bytes_to_write);
342    
343     if (bytes_written == -1) {
344     if (errno == EWOULDBLOCK || errno == EAGAIN)
345     return -1; /* request blocked at the pipe level, but keep going */
346     else if (errno == EINTR)
347     return 1;
348     else if (errno == ENOSPC) {
349     /* 20010520 - Alfred Fluckiger */
350     /* No test was originally done in this case, which might */
351     /* lead to a "no space left on device" error. */
352     boa_perror(req, "write body"); /* OK to disable if your logs get too big */
353     return 0;
354     } else {
355     boa_perror(req, "write body"); /* OK to disable if your logs get too big */
356     return 0;
357     }
358     }
359 nmav 1.1 #ifdef FASCIST_LOGGING
360 nmav 1.2 log_error_time();
361     fprintf(stderr, "%s:%d - wrote %d bytes. %ld of %ld\n",
362     __FILE__, __LINE__, bytes_written, req->filepos, req->filesize);
363 nmav 1.1 #endif
364    
365 nmav 1.2 req->filepos += bytes_written;
366     req->header_line += bytes_written;
367 nmav 1.1
368 nmav 1.2 return 1; /* more to do */
369 nmav 1.1 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26