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

Contents of /hydra/src/response.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations)
Sun Sep 29 11:00:04 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.8: +34 -2 lines
File MIME type: text/plain
Added support for If-Range, If-Match, If-None-Match HTTP/1.1 header
fields. The server also generates ETag headers for static content using
the last modified field of the file, and the file size.

Fixed the behaviour of the range parser, when a bogus range was received.
Now it does not send any message, it silently ignores the bogus range.

1 /*
2 * Hydra, an http server
3 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4 * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
5 * Some changes Copyright (C) 1996-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: response.c,v 1.8 2002/09/28 16:32:37 nmav Exp $*/
24
25 #include "boa.h"
26
27 void print_content_type(request * req)
28 {
29 req_write(req, "Content-Type: ");
30 req_write(req, get_mime_type(req->request_uri));
31 req_write(req, "\r\n");
32 }
33
34 void print_content_length(request * req)
35 {
36 char buf[22];
37
38 simple_itoa( (req->range_stop)-(req->range_start), buf);
39 req_write(req, "Content-Length: ");
40 req_write(req, buf);
41 req_write(req, "\r\n");
42 }
43
44 void print_content_range(request * req)
45 {
46 char start[22];
47 char stop[22];
48 char total[22];
49 char buf[22*3 + 5];
50
51 req_write(req, "Content-Range: bytes ");
52
53 simple_itoa( req->range_stop, stop);
54 simple_itoa( req->range_start, start);
55 simple_itoa( req->filesize, total);
56
57 sprintf( buf, "%s-%s/%s\r\n", start, stop, total);
58 req_write(req, buf);
59 }
60
61 void print_last_modified(request * req)
62 {
63 char lm[] = "Last-Modified: "
64 " " "\r\n";
65 rfc822_time_buf(lm + 15, req->last_modified);
66 req_write(req, lm);
67 }
68
69 void print_etag(request * req)
70 {
71 char buffer[sizeof("ETag: \"\"-\r\n") + MAX_ETAG_LENGTH + 3];
72
73 sprintf( buffer, "ETag: \"%lu-%lu\"\r\n", req->last_modified % 10000,
74 req->filesize % 10000);
75 /* mod 10000 is used to allow no more than 4 characters -- max is 9999
76 */
77 req_write(req, buffer);
78 }
79
80 void print_ka_phrase(request * req)
81 {
82
83 if (req->kacount > 0 &&
84 req->keepalive == KA_ACTIVE && req->response_status < 500) {
85 char buf[22];
86 req_write(req, "Connection: Keep-Alive\r\nKeep-Alive: timeout=");
87 simple_itoa(ka_timeout, buf);
88 req_write(req, buf);
89 req_write(req, ", max=");
90 simple_itoa(req->kacount, buf);
91 req_write(req, buf);
92 req_write(req, "\r\n");
93 } else
94 req_write(req, "Connection: close\r\n");
95 }
96
97 extern char * version;
98
99 void print_http_headers(request * req)
100 {
101 char date_stuff[] = "Date: "
102 " "
103 "\r\n";
104
105 static char tls_version_stuff[64] = "\0";
106 static char version_stuff[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
107
108 #ifdef ENABLE_SSL
109 if ( tls_version_stuff[0] == 0) {
110 strcpy( tls_version_stuff, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
111 strcat( tls_version_stuff, gnutls_check_version(NULL));
112 strcat( tls_version_stuff, "\r\n");
113 }
114 #endif
115
116 rfc822_time_buf(date_stuff + 6, 0);
117
118 req_write(req, date_stuff);
119
120 if (!req->secure)
121 req_write(req, version_stuff);
122 else
123 req_write(req, tls_version_stuff);
124
125 req_write(req, "Accept-Ranges: bytes\r\n");
126 print_ka_phrase(req);
127 }
128
129 /* The routines above are only called by the routines below.
130 * The rest of Hydra only enters through the routines below.
131 */
132
133 /* R_REQUEST_OK: 200 */
134 void send_r_request_ok(request * req)
135 {
136 req->response_status = R_REQUEST_OK;
137 if (req->simple)
138 return;
139
140 req_write(req, HTTP_VERSION" 200 OK\r\n");
141 print_http_headers(req);
142
143 if (!req->is_cgi) {
144 print_content_length(req);
145 print_last_modified(req);
146 print_etag(req);
147 print_content_type(req);
148 req_write(req, "\r\n");
149 }
150 }
151
152 /* R_REQUEST_PARTIAL: 206 */
153 void send_r_request_partial(request * req)
154 {
155 req->response_status = R_REQUEST_PARTIAL;
156 if (req->simple)
157 return;
158
159 req_write(req, HTTP_VERSION" 206 Partial content\r\n");
160 print_http_headers(req);
161
162 if (!req->is_cgi) {
163 print_content_length(req);
164 print_content_range(req);
165 print_last_modified(req);
166 print_content_type(req);
167 req_write(req, "\r\n");
168 }
169 }
170
171 /* R_MOVED_PERM: 301 */
172 void send_r_moved_perm(request * req, char *url)
173 {
174 SQUASH_KA(req);
175 req->response_status = R_MOVED_PERM;
176 if (!req->simple) {
177 req_write(req, HTTP_VERSION" 301 Moved Permanently\r\n");
178 print_http_headers(req);
179 req_write(req, "Content-Type: " TEXT_HTML "\r\n");
180
181 req_write(req, "Location: ");
182 req_write_escape_http(req, url);
183 req_write(req, "\r\n\r\n");
184 }
185 if (req->method != M_HEAD) {
186 req_write(req,
187 "<HTML><HEAD><TITLE>301 Moved Permanently</TITLE></HEAD>\n"
188 "<BODY>\n<H1>301 Moved</H1>The document has moved\n"
189 "<A HREF=\"");
190 req_write_escape_html(req, url);
191 req_write(req, "\">here</A>.\n</BODY></HTML>\n");
192 }
193 req_flush(req);
194 }
195
196 /* R_MOVED_TEMP: 302 */
197 void send_r_moved_temp(request * req, char *url, char *more_hdr)
198 {
199 SQUASH_KA(req);
200 req->response_status = R_MOVED_TEMP;
201 if (!req->simple) {
202 req_write(req, HTTP_VERSION" 302 Moved Temporarily\r\n");
203 print_http_headers(req);
204 req_write(req, "Content-Type: " TEXT_HTML "\r\n");
205
206 req_write(req, "Location: ");
207 req_write_escape_http(req, url);
208 req_write(req, "\r\n");
209 req_write(req, more_hdr);
210 req_write(req, "\r\n\r\n");
211 }
212 if (req->method != M_HEAD) {
213 req_write(req,
214 "<HTML><HEAD><TITLE>302 Moved Temporarily</TITLE></HEAD>\n"
215 "<BODY>\n<H1>302 Moved</H1>The document has moved\n"
216 "<A HREF=\"");
217 req_write_escape_html(req, url);
218 req_write(req, "\">here</A>.\n</BODY></HTML>\n");
219 }
220 req_flush(req);
221 }
222
223 /* R_NOT_MODIFIED: 304 */
224 void send_r_not_modified(request * req)
225 {
226 SQUASH_KA(req);
227 req->response_status = R_NOT_MODIFIED;
228 req_write(req, HTTP_VERSION" 304 Not Modified\r\n");
229 print_http_headers(req);
230 print_content_type(req);
231 req_write(req, "\r\n");
232 req_flush(req);
233 }
234
235 /* R_BAD_REQUEST: 400 */
236 void send_r_bad_request(request * req)
237 {
238 SQUASH_KA(req);
239 req->response_status = R_BAD_REQUEST;
240 if (!req->simple) {
241 req_write(req, HTTP_VERSION" 400 Bad Request\r\n");
242 print_http_headers(req);
243 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
244 }
245 if (req->method != M_HEAD)
246 req_write(req,
247 "<HTML><HEAD><TITLE>400 Bad Request</TITLE></HEAD>\n"
248 "<BODY><H1>400 Bad Request</H1>\nYour client has issued "
249 "a malformed or illegal request.\n</BODY></HTML>\n");
250 req_flush(req);
251 }
252
253 /* R_UNAUTHORIZED: 401 */
254 void send_r_unauthorized(request * req, char *realm_name)
255 {
256 SQUASH_KA(req);
257 req->response_status = R_UNAUTHORIZED;
258 if (!req->simple) {
259 req_write(req, HTTP_VERSION" 401 Unauthorized\r\n");
260 print_http_headers(req);
261 req_write(req, "WWW-Authenticate: Basic realm=\"");
262 req_write(req, realm_name);
263 req_write(req, "\"\r\n");
264 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
265 }
266 if (req->method != M_HEAD) {
267 req_write(req,
268 "<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>\n"
269 "<BODY><H1>401 Unauthorized</H1>\nYour client does not "
270 "have permission to get URL ");
271 req_write_escape_html(req, req->request_uri);
272 req_write(req, " from this server.\n</BODY></HTML>\n");
273 }
274 req_flush(req);
275 }
276
277 /* R_FORBIDDEN: 403 */
278 void send_r_forbidden(request * req)
279 {
280 SQUASH_KA(req);
281 req->response_status = R_FORBIDDEN;
282 if (!req->simple) {
283 req_write(req, HTTP_VERSION" 403 Forbidden\r\n");
284 print_http_headers(req);
285 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
286 }
287 if (req->method != M_HEAD) {
288 req_write(req, "<HTML><HEAD><TITLE>403 Forbidden</TITLE></HEAD>\n"
289 "<BODY><H1>403 Forbidden</H1>\nYour client does not "
290 "have permission to get URL ");
291 req_write_escape_html(req, req->request_uri);
292 req_write(req, " from this server.\n</BODY></HTML>\n");
293 }
294 req_flush(req);
295 }
296
297 /* R_NOT_FOUND: 404 */
298 void send_r_not_found(request * req)
299 {
300 SQUASH_KA(req);
301 req->response_status = R_NOT_FOUND;
302 if (!req->simple) {
303 req_write(req, HTTP_VERSION" 404 Not Found\r\n");
304 print_http_headers(req);
305 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
306 }
307 if (req->method != M_HEAD) {
308 req_write(req, "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n"
309 "<BODY><H1>404 Not Found</H1>\nThe requested URL ");
310 req_write_escape_html(req, req->request_uri);
311 req_write(req, " was not found on this server.\n</BODY></HTML>\n");
312 }
313 req_flush(req);
314 }
315
316 /* R_PRECONDITION_FAILED: 412 */
317 void send_r_precondition_failed(request * req)
318 {
319 req->response_status = R_PRECONDITION_FAILED;
320 if (req->simple)
321 return;
322
323 if (!req->simple) {
324 req_write(req, HTTP_VERSION" 412 Precondition Failed\r\n");
325 print_http_headers(req);
326 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
327 }
328 if (req->method != M_HEAD) {
329 req_write(req, "<HTML><HEAD><TITLE>412 Precondition Failed</TITLE></HEAD>\n"
330 "<BODY><H1>412 Precondition failed</H1>\n");
331
332 req_write(req, "</BODY></HTML>\n");
333 }
334 req_flush(req);
335 }
336
337 /* R_RANGE_UNSATISFIABLE: 416 */
338 void send_r_range_unsatisfiable(request * req)
339 {
340 req->response_status = R_RANGE_UNSATISFIABLE;
341 if (req->simple)
342 return;
343
344 if (!req->simple) {
345 req_write(req, HTTP_VERSION" 416 Range Not Satisfiable\r\n");
346 print_http_headers(req);
347 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
348 }
349 if (req->method != M_HEAD) {
350 char int1[22], int2[22];
351 char range[45];
352 req_write(req, "<HTML><HEAD><TITLE>416 Range Not Satisfiable</TITLE></HEAD>\n"
353 "<BODY><H1>416 Range Not Satisfiable</H1>\nThe requested range URL ");
354 req_write_escape_html(req, req->request_uri);
355 req_write( req, " had illegal range( ");
356
357 simple_itoa( req->range_start, int1);
358 simple_itoa( req->range_stop, int2);
359 sprintf( range, "%s-%s", int1, int2);
360 req_write(req, range);
361 req_write(req, " ).\n</BODY></HTML>\n");
362 }
363 req_flush(req);
364 }
365
366 /* R_ERROR: 500 */
367 void send_r_error(request * req)
368 {
369 SQUASH_KA(req);
370 req->response_status = R_ERROR;
371 if (!req->simple) {
372 req_write(req, HTTP_VERSION" 500 Server Error\r\n");
373 print_http_headers(req);
374 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
375 }
376 if (req->method != M_HEAD) {
377 req_write(req,
378 "<HTML><HEAD><TITLE>500 Server Error</TITLE></HEAD>\n"
379 "<BODY><H1>500 Server Error</H1>\nThe server encountered "
380 "an internal error and could not complete your request.\n"
381 "</BODY></HTML>\n");
382 }
383 req_flush(req);
384 }
385
386 /* R_NOT_IMP: 501 */
387 void send_r_not_implemented(request * req)
388 {
389 SQUASH_KA(req);
390 req->response_status = R_NOT_IMP;
391 if (!req->simple) {
392 req_write(req, HTTP_VERSION" 501 Not Implemented\r\n");
393 print_http_headers(req);
394 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
395 }
396 if (req->method != M_HEAD) {
397 req_write(req,
398 "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>\n"
399 "<BODY><H1>501 Not Implemented</H1>\nPOST to non-script "
400 "is not supported in Hydra.\n</BODY></HTML>\n");
401 }
402 req_flush(req);
403 }
404
405 /* R_BAD_GATEWAY: 502 */
406 void send_r_bad_gateway(request * req)
407 {
408 SQUASH_KA(req);
409 req->response_status = R_BAD_GATEWAY;
410 if (!req->simple) {
411 req_write(req, HTTP_VERSION" 502 Bad Gateway" CRLF);
412 print_http_headers(req);
413 req_write(req, "Content-Type: " TEXT_HTML CRLF CRLF); /* terminate header */
414 }
415 if (req->method != M_HEAD) {
416 req_write(req,
417 "<HTML><HEAD><TITLE>502 Bad Gateway</TITLE></HEAD>\n"
418 "<BODY><H1>502 Bad Gateway</H1>\nThe CGI was "
419 "not CGI/1.1 compliant.\n" "</BODY></HTML>\n");
420 }
421 req_flush(req);
422 }
423
424 /* R_SERVICE_UNAVAILABLE: 503 */
425 void send_r_service_unavailable(request * req) /* 503 */
426 {
427 static const char body[] =
428 "<HTML><HEAD><TITLE>503 Service Unavailable</TITLE></HEAD>\n"
429 "<BODY><H1>503 Service Unavailable</H1>\n"
430 "There are too many connections in use right now.\r\n"
431 "Please try again later.\r\n</BODY></HTML>\n";
432 static int _body_len;
433 static char body_len[22];
434
435 if (!_body_len)
436 _body_len = strlen(body);
437 if (!body_len[0])
438 simple_itoa( _body_len, body_len);
439
440 SQUASH_KA(req);
441 req->response_status = R_SERVICE_UNAV;
442 if (!req->simple) {
443 req_write(req, HTTP_VERSION" 503 Service Unavailable\r\n");
444 print_http_headers(req);
445 if (body_len) {
446 req_write(req, "Content-Length: ");
447 req_write(req, body_len);
448 req_write(req, "\r\n");
449 }
450 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header
451 */
452 }
453 if (req->method != M_HEAD) {
454 req_write(req, body);
455 }
456 req_flush(req);
457 }
458
459
460 /* R_NOT_IMP: 505 */
461 void send_r_bad_version(request * req)
462 {
463 SQUASH_KA(req);
464 req->response_status = R_BAD_VERSION;
465 if (!req->simple) {
466 req_write(req, HTTP_VERSION" 505 HTTP Version Not Supported\r\n");
467 print_http_headers(req);
468 req_write(req, "Content-Type: " TEXT_HTML "\r\n\r\n"); /* terminate header */
469 }
470 if (req->method != M_HEAD) {
471 req_write(req,
472 "<HTML><HEAD><TITLE>505 HTTP Version Not Supported</TITLE></HEAD>\n"
473 "<BODY><H1>505 HTTP Version Not Supported</H1>\nHTTP versions "
474 "other than 0.9 and 1.0 "
475 "are not supported in Hydra.\n<p><p>Version encountered: ");
476 req_write(req, req->http_version);
477 req_write(req, "<p><p></BODY></HTML>\n");
478 }
479 req_flush(req);
480 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26