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

Contents of /hydra/src/response.c

Parent Directory Parent Directory | Revision Log Revision Log


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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26