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

Contents of /hydra/src/read.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Wed Jan 22 07:51:50 2003 UTC (21 years, 2 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 /*
2 * Hydra, an http server
3 * 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 /* $Id: read.c,v 1.6.2.1 2003/01/17 17:19:15 nmav Exp $*/
24
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
41 read_header(server_params *params, request *req)
42 {
43 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
52 #ifdef VERY_FASCIST_LOGGING
53 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
100 #ifdef VERY_FASCIST_LOGGING
101 log_error_time();
102 fprintf(stderr, "status, check: %d, %d\n", req->status, *check);
103 #endif
104
105 req->parse_pos++; /* update parse position */
106 check++;
107
108 if (req->status == ONE_LF) {
109 *req->header_end = '\0';
110
111 /* terminate string that begins at req->header_line */
112
113 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 #ifdef VERY_FASCIST_LOGGING
127 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 #else
133 int retval = process_header_end(params, req);
134 #endif
135 /* 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 #ifdef VERY_FASCIST_LOGGING
198 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 #ifdef FASCIST_LOGGING1
235 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 #ifdef VERY_FASCIST_LOGGING2
240 req->client_stream + req->client_stream_pos - bytes);
241 #else
242 "");
243 #endif
244 #endif
245 }
246 return 1;
247 } /* read_header() */
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
269 read_body(request *req)
270 {
271 int bytes_read, bytes_to_read, bytes_free;
272
273 bytes_free = BUFFER_SIZE - (req->header_end - req->header_line);
274 bytes_to_read = req->filesize - req->filepos;
275
276 if (bytes_to_read > bytes_free)
277 bytes_to_read = bytes_free;
278
279 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
303 req->status = BODY_WRITE;
304
305 #ifdef FASCIST_LOGGING1
306 log_error_time();
307 fprintf(stderr, "%s:%d - read %d bytes.\n",
308 __FILE__, __LINE__, bytes_to_read);
309 #endif
310
311 req->header_end += bytes_read;
312
313 return 1;
314 }
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 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 write(req->post_data_fd.fds[1], 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 #ifdef FASCIST_LOGGING
360 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 #endif
364
365 req->filepos += bytes_written;
366 req->header_line += bytes_written;
367
368 return 1; /* more to do */
369 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26