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

Annotation of /hydra/src/read.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (hide annotations)
Wed Jan 22 07:51:50 2003 UTC (21 years, 3 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_1_7, hydra_0_1_6, hydra_0_1_4, hydra_0_1_8, HEAD
Changes since 1.8: +14 -14 lines
File MIME type: text/plain
merged changes from 0.1.x branch.

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.9 /* $Id: read.c,v 1.6.2.1 2003/01/17 17:19:15 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 andreou 1.7 int
41     read_header(server_params *params, request *req)
42 nmav 1.1 {
43 andreou 1.7 int bytes,
44     buf_bytes_left;
45     char *check,
46     *buffer;
47    
48     check = req->client_stream + req->parse_pos;
49     buffer = req->client_stream;
50     bytes = req->client_stream_pos;
51 nmav 1.1
52     #ifdef VERY_FASCIST_LOGGING
53 andreou 1.7 if (check < (buffer + bytes)) {
54     buffer[bytes] = '\0';
55     log_error_time();
56     fprintf(stderr, "%s:%d - Parsing headers (\"%s\")\n",
57     __FILE__, __LINE__, check);
58     }
59     #endif
60     while (check < (buffer + bytes)) {
61     switch (req->status) {
62     case READ_HEADER:
63     if (*check == '\r') {
64     req->status = ONE_CR;
65     req->header_end = check;
66     } else if (*check == '\n') {
67     req->status = ONE_LF;
68     req->header_end = check;
69     }
70     break;
71    
72     case ONE_CR:
73     if (*check == '\n')
74     req->status = ONE_LF;
75     else if (*check != '\r')
76     req->status = READ_HEADER;
77     break;
78    
79     case ONE_LF:
80     /* if here, we've found the end (for sure) of a header */
81     if (*check == '\r') /* could be end of headers */
82     req->status = TWO_CR;
83     else if (*check == '\n')
84     req->status = BODY_READ;
85     else
86     req->status = READ_HEADER;
87     break;
88    
89     case TWO_CR:
90     if (*check == '\n')
91     req->status = BODY_READ;
92     else if (*check != '\r')
93     req->status = READ_HEADER;
94     break;
95    
96     default:
97     break;
98     }
99 nmav 1.1
100     #ifdef VERY_FASCIST_LOGGING
101 andreou 1.7 log_error_time();
102     fprintf(stderr, "status, check: %d, %d\n", req->status, *check);
103 nmav 1.1 #endif
104    
105 andreou 1.7 req->parse_pos++; /* update parse position */
106     check++;
107 nmav 1.1
108 andreou 1.7 if (req->status == ONE_LF) {
109     *req->header_end = '\0';
110    
111     /* terminate string that begins at req->header_line */
112    
113 nmav 1.9 if (req->logline) {
114     if (process_option_line(req) == 0) {
115     return 0;
116     }
117     } else {
118     if (process_logline(req) == 0)
119     return 0;
120     if (req->http_version == HTTP_0_9)
121     return process_header_end(params, req);
122     }
123     /* set header_line to point to beginning of new header */
124     req->header_line = check;
125     } else if (req->status == BODY_READ) {
126 nmav 1.1 #ifdef VERY_FASCIST_LOGGING
127 andreou 1.7 int retval;
128     log_error_time();
129     fprintf(stderr, "%s:%d -- got to body read.\n",
130     __FILE__, __LINE__);
131     retval = process_header_end(params, req);
132 nmav 1.1 #else
133 andreou 1.7 int retval = process_header_end(params, req);
134 nmav 1.1 #endif
135 andreou 1.7 /* process_header_end inits non-POST cgi's */
136    
137     if (retval && req->method == M_POST) {
138     /* for body_{read,write}, set header_line to start of data,
139     and header_end to end of data */
140     req->header_line = check;
141     req->header_end = req->client_stream + req->client_stream_pos;
142    
143     req->status = BODY_WRITE;
144     /* so write it */
145     /* have to write first, or read will be confused
146     * because of the special case where the
147     * filesize is less than we have already read.
148     */
149    
150     /*
151    
152     As quoted from RFC1945:
153    
154     A valid Content-Length is required on all HTTP/1.0 POST requests. An
155     HTTP/1.0 server should respond with a 400 (bad request) message if it
156     cannot determine the length of the request message's content.
157    
158     */
159    
160     if (req->content_length) {
161     int content_length;
162    
163     content_length = boa_atoi(req->content_length);
164     /* Is a content-length of 0 legal? */
165     if (content_length < 0) {
166     log_error_time();
167     fprintf(stderr,
168     "Invalid Content-Length [%s] on POST!\n",
169     req->content_length);
170     send_r_bad_request(req);
171     return 0;
172     }
173     if (single_post_limit && content_length > single_post_limit) {
174     log_error_time();
175     fprintf(stderr,
176     "Content-Length [%d] > SinglePostLimit [%d] on POST!\n",
177     content_length, single_post_limit);
178     send_r_bad_request(req);
179     return 0;
180     }
181     req->filesize = content_length;
182     req->filepos = 0;
183     if (req->header_end - req->header_line > req->filesize) {
184     req->header_end = req->header_line + req->filesize;
185     }
186     } else {
187     log_error_time();
188     fprintf(stderr, "Unknown Content-Length POST!\n");
189     send_r_bad_request(req);
190     return 0;
191     }
192     } /* either process_header_end failed or req->method != POST */
193     return retval; /* 0 - close it done, 1 - keep on ready */
194     } /* req->status == BODY_READ */
195     } /* done processing available buffer */
196    
197 nmav 1.1 #ifdef VERY_FASCIST_LOGGING
198 andreou 1.7 log_error_time();
199     fprintf(stderr, "%s:%d - Done processing buffer. Status: %d\n",
200     __FILE__, __LINE__, req->status);
201     #endif
202    
203     if (req->status < BODY_READ) {
204     /* only reached if request is split across more than one packet */
205    
206     buf_bytes_left = CLIENT_STREAM_SIZE - req->client_stream_pos;
207     if (buf_bytes_left < 1) {
208     log_error_time();
209     fputs("buffer overrun - read.c, read_header - closing\n", stderr);
210     req->status = DEAD;
211     return 0;
212     }
213    
214     bytes = socket_recv(req, buffer + req->client_stream_pos,
215     buf_bytes_left);
216    
217     if (bytes < 0) {
218     if (bytes == BOA_E_INTR)
219     return 1;
220     if (bytes == BOA_E_AGAIN)
221     return -1;
222    
223     log_error_doc(req);
224     perror("header read"); /* don't need to save errno because log_error_doc does */
225     return 0;
226     } else if (bytes == 0) {
227     /* this is an error. premature end of headers! */
228     return 0;
229     }
230    
231     /* bytes is positive */
232     req->client_stream_pos += bytes;
233    
234 nmav 1.1 #ifdef FASCIST_LOGGING1
235 andreou 1.7 log_error_time();
236     req->client_stream[req->client_stream_pos] = '\0';
237     fprintf(stderr, "%s:%d -- We read %d bytes: \"%s\"\n",
238     __FILE__, __LINE__, bytes,
239 nmav 1.1 #ifdef VERY_FASCIST_LOGGING2
240 andreou 1.7 req->client_stream + req->client_stream_pos - bytes);
241 nmav 1.1 #else
242 andreou 1.7 "");
243 nmav 1.1 #endif
244     #endif
245 nmav 1.8 }
246 andreou 1.7 return 1;
247     } /* read_header() */
248 nmav 1.1
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 andreou 1.7 int
269     read_body(request *req)
270 nmav 1.1 {
271 andreou 1.7 int bytes_read, bytes_to_read, bytes_free;
272 nmav 1.1
273 andreou 1.7 bytes_free = BUFFER_SIZE - (req->header_end - req->header_line);
274     bytes_to_read = req->filesize - req->filepos;
275 nmav 1.1
276 nmav 1.2 if (bytes_to_read > bytes_free)
277     bytes_to_read = bytes_free;
278 nmav 1.1
279 nmav 1.2 if (bytes_to_read <= 0) {
280     req->status = BODY_WRITE; /* go write it */
281     return 1;
282     }
283    
284     bytes_read = socket_recv(req, req->header_end, bytes_to_read);
285    
286     if (bytes_read < 0) {
287     if (bytes_read == BOA_E_AGAIN) {
288     return -1;
289     } else {
290     boa_perror(req, "read body");
291     return 0;
292     }
293    
294     } else if (bytes_read == 0) {
295     /* this is an error. premature end of body! */
296     log_error_time();
297     fprintf(stderr, "%s:%d - Premature end of body!!\n",
298     __FILE__, __LINE__);
299     send_r_bad_request(req);
300     return 0;
301     }
302 nmav 1.1
303 nmav 1.2 req->status = BODY_WRITE;
304 nmav 1.1
305     #ifdef FASCIST_LOGGING1
306 nmav 1.2 log_error_time();
307     fprintf(stderr, "%s:%d - read %d bytes.\n",
308     __FILE__, __LINE__, bytes_to_read);
309 nmav 1.1 #endif
310    
311 nmav 1.2 req->header_end += bytes_read;
312 nmav 1.1
313 nmav 1.2 return 1;
314 nmav 1.1 }
315    
316     /*
317     * Name: write_body
318     * Description: Writes a chunk of data to a file
319     *
320     * Return values:
321     * -1: request blocked, move to blocked queue
322     * 0: EOF or error, close it down
323     * 1: successful write, recycle in ready queue
324     */
325    
326     int write_body(request * req)
327     {
328 nmav 1.2 int bytes_written, bytes_to_write = req->header_end - req->header_line;
329     if (req->filepos + bytes_to_write > req->filesize)
330     bytes_to_write = req->filesize - req->filepos;
331    
332     if (bytes_to_write == 0) { /* nothing left in buffer to write */
333     req->header_line = req->header_end = req->buffer;
334     if (req->filepos >= req->filesize)
335     return init_cgi(req);
336     /* if here, we can safely assume that there is more to read */
337     req->status = BODY_READ;
338     return 1;
339     }
340     bytes_written =
341 nmav 1.6 write(req->post_data_fd.fds[1], req->header_line, bytes_to_write);
342 nmav 1.2
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