Annotation of embedaddon/libpdel/http/http_response.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43: #include <sys/queue.h>
44:
45: #include <netinet/in.h>
46:
47: #include <stdio.h>
48: #include <stdlib.h>
49: #include <stdarg.h>
50: #include <string.h>
51: #include <pthread.h>
52: #include <limits.h>
53: #include <ctype.h>
54: #include <syslog.h>
55: #include <errno.h>
56: #include <assert.h>
57:
58: #include <openssl/ssl.h>
59:
60: #include "structs/structs.h"
61: #include "structs/type/array.h"
62:
63: #include "http/http_defs.h"
64: #include "http/http_server.h"
65: #include "http/http_internal.h"
66: #include "util/typed_mem.h"
67:
68: struct suffix_map {
69: const char *suffix;
70: const char *mime;
71: };
72:
73: /* error responses */
74: #define MALFORMED_RESPONSE_MSG "Malformed response"
75: #define TIMEOUT_RESPONSE_MSG "Server timed out"
76:
77: /*
78: * Internal functions
79: */
80: static int suffix_cmp(const void *v1, const void *v2);
81:
82: /* Filename suffix -> MIME encoding (list is sorted case insensitively) */
83: static const struct suffix_map mime_encodings[] = {
84: { "gz", "gzip" },
85: { "uu", "x-uuencode" },
86: { "Z", "compress" },
87: };
88: static const int num_mime_encodings
89: = sizeof(mime_encodings) / sizeof(*mime_encodings);
90:
91: /* Filename suffix -> MIME type (list is sorted case insensitively) */
92: static const struct suffix_map mime_types[] = {
93: { "a", "application/octet-stream" },
94: { "aab", "application/x-authorware-bin" },
95: { "aam", "application/x-authorware-map" },
96: { "aas", "application/x-authorware-seg" },
97: { "ai", "application/postscript" },
98: { "aif", "audio/x-aiff" },
99: { "aifc", "audio/x-aiff" },
100: { "aiff", "audio/x-aiff" },
101: { "au", "audio/basic" },
102: { "avi", "video/x-msvideo" },
103: { "bcpio", "application/x-bcpio" },
104: { "bin", "application/octet-stream" },
105: { "cdf", "application/x-netcdf" },
106: { "class", "application/java" },
107: { "cpio", "application/x-cpio" },
108: { "css", "text/css" },
109: { "dcr", "application/x-director" },
110: { "dir", "application/x-director" },
111: { "doc", "application/msword" },
112: { "dtd", "text/xml" },
113: { "dump", "application/octet-stream" },
114: { "dvi", "application/x-dvi" },
115: { "dxr", "application/x-director" },
116: { "eps", "application/postscript" },
117: { "etx", "text/x-setext" },
118: { "exe", "application/octet-stream" },
119: { "fgd", "application/x-director" },
120: { "fh", "image/x-freehand" },
121: { "fh4", "image/x-freehand" },
122: { "fh5", "image/x-freehand" },
123: { "fh7", "image/x-freehand" },
124: { "fhc", "image/x-freehand" },
125: { "gif", "image/gif" },
126: { "gtar", "application/x-gtar" },
127: { "hdf", "application/x-hdf" },
128: { "hqx", "application/mac-binhex40" },
129: { "htm", "text/html" },
130: { "html", "text/html" },
131: { "ief", "image/ief" },
132: { "iv", "application/x-inventor" },
133: { "jfif", "image/jpeg" },
134: { "jpe", "image/jpeg" },
135: { "jpeg", "image/jpeg" },
136: { "jpg", "image/jpeg" },
137: { "js", "application/x-javascript" },
138: { "kar", "audio/midi" },
139: { "latex", "application/x-latex" },
140: { "man", "application/x-troff-man" },
141: { "man", "application/x-troff-man" },
142: { "me", "application/x-troff-me" },
143: { "me", "application/x-troff-me" },
144: { "mid", "audio/midi" },
145: { "midi", "audio/midi" },
146: { "mif", "application/x-mif" },
147: { "mime", "message/rfc822" },
148: { "mmf", "application/x-www-urlformencoded" },
149: { "mov", "video/quicktime" },
150: { "movie", "video/x-sgi-movie" },
151: { "mp2", "audio/mpeg" },
152: { "mp3", "audio/mpeg" },
153: { "mpe", "video/mpeg" },
154: { "mpeg", "video/mpeg" },
155: { "mpg", "video/mpeg" },
156: { "mpga", "audio/mpeg" },
157: { "ms", "application/x-troff-ms" },
158: { "ms", "application/x-troff-ms" },
159: { "mv", "video/x-sgi-movie" },
160: { "nc", "application/x-netcdf" },
161: { "o", "application/octet-stream" },
162: { "oda", "application/oda" },
163: { "pac", "application/x-ns-proxy-autoconfig" },
164: { "pbm", "image/x-portable-bitmap" },
165: { "pdf", "application/pdf" },
166: { "pgm", "image/x-portable-graymap" },
167: { "png", "image/png" },
168: { "pnm", "image/x-portable-anymap" },
169: { "ppm", "image/x-portable-pixmap" },
170: { "ppt", "application/powerpoint" },
171: { "ps", "application/postscript" },
172: { "qt", "video/quicktime" },
173: { "ra", "audio/x-pn-realaudio" },
174: { "ram", "audio/x-pn-realaudio" },
175: { "rm", "audio/x-pn-realaudio" },
176: { "roff", "application/x-troff" },
177: { "rpm", "audio/x-pn-realaudio-plugin" },
178: { "rtf", "application/rtf" },
179: { "rtx", "text/richtext" },
180: { "sh", "application/x-shar" },
181: { "shar", "application/x-shar" },
182: { "sit", "application/x-stuffit" },
183: { "snd", "audio/basic" },
184: { "spl", "application/futuresplash" },
185: { "sv4cpio", "application/x-sv4cpio" },
186: { "sv4crc", "application/x-sv4crc" },
187: { "swf", "application/x-shockwave-flash" },
188: { "tar", "application/x-tar" },
189: { "tex", "application/x-tex" },
190: { "texi", "application/x-texinfo" },
191: { "texinfo", "application/x-texinfo" },
192: { "tif", "image/tiff" },
193: { "tiff", "image/tiff" },
194: { "tmpl", "text/plain" }, /* template file input */
195: { "tr", "application/x-troff" },
196: { "tsp", "application/dsptype" },
197: { "tsv", "text/tab-separated-values" },
198: { "txt", "text/plain" },
199: { "ustar", "application/x-ustar" },
200: { "vrml", "model/vrml" },
201: { "vx", "video/x-rad-screenplay" },
202: { "wav", "audio/wav" },
203: { "wbmp", "image/vnd.wap.wbmp" },
204: { "wml", "text/vnd.wap.wml" },
205: { "wmlc", "application/vnd.wap.wmlc" },
206: { "wmls", "text/vnd.wap.wmlscript" },
207: { "wmlsc", "application/vnd.wap.wmlscriptc" },
208: { "wrl", "model/vrml" },
209: { "wsrc", "application/x-wais-source" },
210: { "xbm", "image/x-xbitmap" },
211: { "xml", "text/xml" },
212: { "xpm", "image/x-xpixmap" },
213: { "xwd", "image/x-xwindowdump" },
214: { "zip", "application/x-zip-compressed" },
215: };
216: static const int num_mime_types = sizeof(mime_types) / sizeof(*mime_types);
217:
218: /*********************************************************************
219: MAIN ROUTINES
220: *********************************************************************/
221:
222: /*
223: * Create a new response structure.
224: */
225: int
226: _http_response_new(struct http_connection *conn)
227: {
228: struct http_response *resp;
229:
230: /* Create response structure */
231: assert(conn->resp == NULL);
232: if ((resp = MALLOC("http_response", sizeof(*resp))) == NULL) {
233: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
234: return (-1);
235: }
236: memset(resp, 0, sizeof(*resp));
237:
238: /* Attach message structure */
239: if ((resp->msg = _http_message_new()) == NULL) {
240: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
241: FREE("http_response", resp);
242: return (-1);
243: }
244:
245: /* Link it up */
246: resp->msg->conn = conn;
247: conn->resp = resp;
248: return (0);
249: }
250:
251: /*
252: * Read in, validate, and prep an HTTP response from a connection.
253: *
254: * In all cases, fill in the error message buffer.
255: */
256: int
257: _http_response_read(struct http_connection *conn, char *errbuf, int size)
258: {
259: struct http_response *const resp = conn->resp;
260: const char *hval;
261:
262: /* Load in message from HTTP connection */
263: if (_http_message_read(resp->msg, 0) == -1) {
264: switch (errno) {
265: case EINVAL:
266: strlcpy(errbuf, MALFORMED_RESPONSE_MSG, size);
267: break;
268:
269: case ETIMEDOUT:
270: strlcpy(errbuf, TIMEOUT_RESPONSE_MSG, size);
271: break;
272:
273: default:
274: strlcpy(errbuf, strerror(errno), size);
275: break;
276: }
277:
278: /* fix errno now that we've used it */
279: conn->keep_alive = 0;
280: errno = EINVAL;
281: return (-1);
282: }
283:
284: /* Set code */
285: hval = http_response_get_header(resp, HDR_REPLY_STATUS);
286: if (sscanf(hval, "%u", &resp->code) != 1) {
287: snprintf(errbuf, size, "Invalid response code ``%s''", hval);
288: conn->keep_alive = 0;
289: errno = EINVAL;
290: return (-1);
291: }
292:
293: /* Expect no body from certain responses */
294: if (http_response_no_body(resp->code)) {
295: resp->msg->input_len = 0;
296: resp->msg->no_body = 1;
297: } else if (resp->msg->input_len == UINT_MAX
298: && _http_head_want_keepalive(resp->msg->head)) {
299: snprintf(errbuf, size,
300: "Keep-Alive requres %s", HTTP_HEADER_CONTENT_LENGTH);
301: conn->keep_alive = 0;
302: errno = EINVAL;
303: return (-1);
304: }
305:
306: /* Turn off keep alive if not specified by remote side */
307: if (!_http_head_want_keepalive(resp->msg->head))
308: conn->keep_alive = 0;
309:
310: /* Done */
311: strlcpy(errbuf, http_response_get_header(resp, HDR_REPLY_REASON), size);
312: return (0);
313: }
314:
315: /*
316: * Free a response
317: */
318: void
319: _http_response_free(struct http_response **respp)
320: {
321: struct http_response *const resp = *respp;
322:
323: if (resp == NULL)
324: return;
325: _http_message_free(&resp->msg);
326: FREE("http_response", resp);
327: *respp = NULL;
328: }
329:
330: /*
331: * Get response code.
332: */
333: int
334: http_response_get_code(struct http_response *resp)
335: {
336: return (resp->code);
337: }
338:
339: /*********************************************************************
340: MESSAGE WRAPPERS
341: *********************************************************************/
342:
343: /*
344: * Set a response header.
345: */
346: int
347: http_response_set_header(struct http_response *resp, int append,
348: const char *name, const char *valfmt, ...)
349: {
350: va_list args;
351: int ret;
352:
353: /* Set header */
354: va_start(args, valfmt);
355: ret = _http_message_vset_header(resp->msg, append, name, valfmt, args);
356: va_end(args);
357: if (ret == -1)
358: return (-1);
359:
360: /* Remember response code */
361: if (name == HDR_REPLY_STATUS) {
362: resp->code = atoi(http_response_get_header(resp, name));
363: resp->msg->no_body = http_response_no_body(resp->code);
364: }
365:
366: /* Done */
367: return (0);
368: }
369:
370: /*
371: * Get a response header.
372: *
373: * For headers listed multiple times, this only gets the first instance.
374: */
375: const char *
376: http_response_get_header(struct http_response *resp, const char *name)
377: {
378: return (_http_head_get(resp->msg->head, name));
379: }
380:
381: /*
382: * Get the number of headers
383: */
384: int
385: http_response_num_headers(struct http_response *resp)
386: {
387: return (_http_head_num_headers(resp->msg->head));
388: }
389:
390: /*
391: * Get header by index.
392: */
393: int
394: http_response_get_header_by_index(struct http_response *resp,
395: u_int index, const char **namep, const char **valuep)
396: {
397: return (_http_head_get_by_index(resp->msg->head, index, namep, valuep));
398: }
399:
400: /*
401: * Remove a header.
402: */
403: int
404: http_response_remove_header(struct http_response *resp, const char *name)
405: {
406: return (_http_message_remove_header(resp->msg, name));
407: }
408:
409: /*
410: * Send response headers, if not sent already.
411: */
412: int
413: http_response_send_headers(struct http_response *resp, int unbuffer)
414: {
415: _http_message_send_headers(resp->msg, unbuffer);
416: return (0);
417: }
418:
419: /*
420: * Get response input stream.
421: */
422: FILE *
423: http_response_get_input(struct http_response *resp)
424: {
425: if (resp->msg->conn->server) {
426: errno = EINVAL;
427: return (NULL);
428: }
429: return (resp->msg->input);
430: }
431:
432: /*
433: * Get response output stream.
434: */
435: FILE *
436: http_response_get_output(struct http_response *resp, int buffer)
437: {
438: if (!resp->msg->conn->server) {
439: errno = EINVAL;
440: return (NULL);
441: }
442: return (_http_message_get_output(resp->msg, buffer));
443: }
444:
445: /*
446: * Get raw i/o stream as a file descriptor.
447: */
448: int
449: http_response_get_raw_socket(struct http_response *resp)
450: {
451: return (_http_message_get_raw_socket(resp->msg));
452: }
453:
454: /*
455: * Get remote IP address.
456: */
457: struct in_addr
458: http_response_get_remote_ip(struct http_response *resp)
459: {
460: return (_http_message_get_remote_ip(resp->msg));
461: }
462:
463: /*
464: * Get remote port.
465: */
466: u_int16_t
467: http_response_get_remote_port(struct http_response *resp)
468: {
469: return (_http_message_get_remote_port(resp->msg));
470: }
471:
472: /*
473: * Get SSL context.
474: */
475: SSL_CTX *
476: http_response_get_ssl(struct http_response *resp)
477: {
478: return (resp->msg->conn->ssl);
479: }
480:
481: /*********************************************************************
482: SERVLET HELPERS
483: *********************************************************************/
484:
485: /*
486: * Send an HTTP redirect.
487: */
488: void
489: http_response_send_redirect(struct http_response *resp, const char *url)
490: {
491: const char *name;
492: const char *value;
493:
494: while (_http_head_get_by_index(resp->msg->head, 0, &name, &value) == 0)
495: _http_head_remove(resp->msg->head, name);
496: http_response_set_header(resp, 0, HDR_REPLY_STATUS,
497: "%d", HTTP_STATUS_MOVED_PERMANENTLY);
498: http_response_set_header(resp, 0, HDR_REPLY_REASON,
499: "%s", http_response_status_msg(HTTP_STATUS_MOVED_PERMANENTLY));
500: http_response_set_header(resp, 0, "Location", "%s", url);
501: }
502:
503: /*
504: * Send an HTTP authorization failed response.
505: */
506: void
507: http_response_send_basic_auth(struct http_response *resp, const char *realm)
508: {
509: http_response_set_header(resp, 0, HTTP_HEADER_WWW_AUTHENTICATE,
510: "Basic realm=\"%s\"", realm);
511: _http_head_remove(resp->msg->head, HTTP_HEADER_LAST_MODIFIED);
512: http_response_send_error(resp, HTTP_STATUS_UNAUTHORIZED, NULL);
513: }
514:
515: /*
516: * Convert 'errno' into an HTTP error response.
517: */
518: void
519: http_response_send_errno_error(struct http_response *resp)
520: {
521: int code;
522:
523: switch (errno) {
524: case ENOENT:
525: case ENOTDIR:
526: code = HTTP_STATUS_NOT_FOUND;
527: break;
528: case EPERM:
529: case EACCES:
530: code = HTTP_STATUS_FORBIDDEN;
531: break;
532: default:
533: code = HTTP_STATUS_INTERNAL_SERVER_ERROR;
534: break;
535: }
536: http_response_send_error(resp, code, "%s", strerror(errno));
537: }
538:
539: /*
540: * Send back a simple error page
541: */
542: void
543: http_response_send_error(struct http_response *resp,
544: int code, const char *fmt, ...)
545: {
546: struct http_request *const req = resp->msg->conn->req;
547: const char *ua;
548: FILE *fp;
549: int i;
550:
551: /* Check headers already sent */
552: if (resp->msg->hdrs_sent)
553: return;
554:
555: /* Set response line info */
556: http_response_set_header(resp, 0, HDR_REPLY_STATUS, "%d", code);
557: http_response_set_header(resp, 0, HDR_REPLY_REASON,
558: "%s", http_response_status_msg(code));
559:
560: /* Set additional headers */
561: http_response_set_header(resp, 0, HTTP_HEADER_CONTENT_TYPE,
562: "text/html; charset=iso-8859-1");
563:
564: /* Close connection for real errors */
565: if (code >= 400) {
566: http_response_set_header(resp,
567: 0, _http_message_connection_header(resp->msg), "close");
568: }
569:
570: /* Send error page body */
571: if ((fp = http_response_get_output(resp, 1)) == NULL)
572: return;
573: fprintf(fp, "<HTML>\n<HEAD>\n<TITLE>%d %s</TITLE></HEAD>\n",
574: code, http_response_status_msg(code));
575: fprintf(fp, "<BODY BGCOLOR=\"#FFFFFF\">\n<H3>%d %s</H3>\n",
576: code, http_response_status_msg(code));
577: if (fmt != NULL) {
578: va_list args;
579:
580: fprintf(fp, "<B>");
581: va_start(args, fmt);
582: vfprintf(fp, fmt, args);
583: va_end(args);
584: fprintf(fp, "</B>\n");
585: }
586: #if 0
587: fprintf(fp, "<P></P>\n<HR>\n");
588: fprintf(fp, "<FONT SIZE=\"-1\"><EM>%s</EM></FONT>\n",
589: serv->server_name);
590: #endif
591:
592: /* Add fillter for IE */
593: if ((ua = http_request_get_header(req, HTTP_HEADER_USER_AGENT)) != NULL
594: && strstr(ua, "IE") != NULL) {
595: for (i = 0; i < 20; i++) {
596: fprintf(fp, "<!-- FILLER TO MAKE INTERNET EXPLORER SHOW"
597: " THIS PAGE INSTEAD OF ITS OWN PAGE -->\n");
598: }
599: }
600: fprintf(fp, "</BODY>\n</HTML>\n");
601: }
602:
603: /*
604: * Try to guess MIME type and encoding from filename suffix.
605: */
606: void
607: http_response_guess_mime(const char *path,
608: const char **ctype, const char **cencs, int maxencs)
609: {
610: static char buf[MAXPATHLEN];
611: struct suffix_map *mime;
612: int matched_ctype = -1;
613: struct suffix_map key;
614: const char *slash;
615: char *tokctx;
616: char *s;
617: int i;
618:
619: /* Set defaults */
620: *ctype = "text/plain; charset=iso-8859-1";
621: memset(cencs, 0, maxencs * sizeof(*cencs));
622:
623: /* Strip directories */
624: if ((slash = strrchr(path, '/')) != NULL)
625: path = slash + 1;
626: strlcpy(buf, path, sizeof(buf));
627:
628: /* Search for suffixes matching MIME types table entry */
629: for (i = 0, s = strtok_r(buf, ".", &tokctx);
630: s != NULL; i++, s = strtok_r(NULL, ".", &tokctx)) {
631: key.suffix = s;
632: if ((mime = bsearch(&key, mime_types, num_mime_types,
633: sizeof(*mime_types), suffix_cmp)) != NULL) {
634: *ctype = mime->mime;
635: matched_ctype = i;
636: }
637: }
638: if (matched_ctype == -1)
639: return;
640:
641: /* Skip to the suffix after the last MIME type suffix */
642: for (i = 0, s = strtok_r(buf, ".", &tokctx);
643: i <= matched_ctype; i++, s = strtok_r(NULL, ".", &tokctx));
644:
645: /* Get encoding(s) */
646: for (i = 0; i < maxencs - 1
647: && (s = strtok_r(NULL, ".", &tokctx)) != NULL; i++) {
648: key.suffix = s;
649: if ((mime = bsearch(&key, mime_encodings, num_mime_encodings,
650: sizeof(*mime_encodings), suffix_cmp)) == NULL)
651: break;
652: cencs[i] = mime->mime;
653: }
654: }
655:
656: /*
657: * Compare two entries in MIME type/encoding array
658: */
659: static int
660: suffix_cmp(const void *v1, const void *v2)
661: {
662: const struct suffix_map *const map1 = v1;
663: const struct suffix_map *const map2 = v2;
664:
665: return (strcasecmp(map1->suffix, map2->suffix));
666: }
667:
668: /*********************************************************************
669: MISC ROUTINES
670: *********************************************************************/
671:
672: /*
673: * Certain response codes are required to not have any body.
674: */
675: int
676: http_response_no_body(int code)
677: {
678: switch (code) {
679: case HTTP_STATUS_NO_CONTENT:
680: case HTTP_STATUS_NOT_MODIFIED:
681: return (1);
682: }
683: return (0);
684: }
685:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>