Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_request.c, revision 1.1.1.2
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/queue.h>
43:
44: #include <netinet/in.h>
45:
46: #include <stdio.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <string.h>
50: #include <limits.h>
51: #include <pthread.h>
52: #include <ctype.h>
53: #include <syslog.h>
54: #include <errno.h>
55: #include <assert.h>
56:
57: #include <openssl/ssl.h>
58:
59: #include "structs/structs.h"
60: #include "structs/type/array.h"
61:
62: #include "http/http_defs.h"
63: #include "http/http_server.h"
64: #include "http/http_internal.h"
65: #include "util/typed_mem.h"
66:
67: #define MAX_NVP_LEN (8 * 1024)
68: #define MAX_NVP_DATA (64 * 1024)
69:
70: /*
71: * Error strings
72: */
73: #define PARSE_REQUST_MSG "Error parsing request header"
74: #define REQUEST_TIMEOUT_MSG "Press reload to reestablish a connection"
75:
76: /*
77: * Internal functions
78: */
79: static int http_request_decode_query(struct http_request *req);
80: static int nvp_cmp(const void *v1, const void *v2);
81: static char *read_string_until(const char *mtype,
82: FILE *fp, const char *term);
83: static int http_request_add_nvp(struct http_request *req, int encoded,
84: const char *ename, const char *evalue);
85: static void http_request_decode_auth(struct http_request *req);
86:
87: /*
88: * Internal variables
89: */
90: static const char base64[65]
91: = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
92:
93: /*********************************************************************
94: MAIN ROUTINES
95: *********************************************************************/
96:
97: /*
98: * Create a new request structure.
99: */
100: int
101: _http_request_new(struct http_connection *conn)
102: {
103: struct http_request *req;
104:
105: /* Create request structure */
106: assert(conn->req == NULL);
107: if ((req = MALLOC("http_request", sizeof(*req))) == NULL) {
108: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
109: return (-1);
110: }
111: memset(req, 0, sizeof(*req));
112:
113: /* Attach message structure */
114: if ((req->msg = _http_message_new()) == NULL) {
115: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
116: FREE("http_request", req);
117: return (-1);
118: }
119:
120: /* Link it up */
121: req->msg->conn = conn;
122: conn->req = req;
123: return (0);
124: }
125:
126: /*
127: * Read in, validate, and prep an HTTP request from a connection.
128: *
129: * If there is a problem, load an error response page if appropriate.
130: */
131: int
132: _http_request_read(struct http_connection *conn)
133: {
134: struct http_request *const req = conn->req;
135: struct http_response *const resp = conn->resp;
136: struct http_message *const msg = req->msg;
137: const char *path = NULL;
138: const char *method;
139: const char *colon;
140: const char *slash;
141: const char *proto;
142: const char *uri;
143: const char *s;
144: char scheme[32];
145: int plen = -1;
146: int hlen;
147:
148: /* Load in message from HTTP connection */
149: if (_http_message_read(msg, 1) == -1) {
150: const int errno_save = errno;
151:
152: /* If nothing read, the peer must have closed the connection */
153: if (!_http_message_has_anything(msg)) {
154: errno = ENOTCONN;
155: return (-1);
156: }
157:
158: /* Return an appropriate error message */
159: switch (errno) {
160: case EINVAL:
161: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
162: PARSE_REQUST_MSG);
163: break;
164:
165: case ETIMEDOUT:
166: http_response_send_error(resp,
167: HTTP_STATUS_REQUEST_TIME_OUT, REQUEST_TIMEOUT_MSG);
168: break;
169:
170: default:
171: http_response_send_error(resp,
172: HTTP_STATUS_INTERNAL_SERVER_ERROR,
173: "%s", strerror(errno));
174: break;
175: }
176:
177: /* in all cases return -1 */
178: errno = errno_save;
179: return (-1);
180: }
181:
182: /* Get method, URI, and protocol */
183: method = _http_head_get(msg->head, HDR_REQUEST_METHOD);
184: uri = _http_head_get(msg->head, HDR_REQUEST_URI);
185: proto = _http_head_get(msg->head, HDR_REQUEST_VERSION);
186:
187: /* Check method and reset input length if not POST */
188: if (strcmp(method, HTTP_METHOD_GET) == 0
189: || strcmp(method, HTTP_METHOD_HEAD) == 0
190: || strcmp(method, HTTP_METHOD_POST) == 0
191: || strcmp(method, HTTP_METHOD_CONNECT) == 0)
192: ; /* ok */
193: else if (strcmp(method, HTTP_METHOD_OPTIONS) == 0
194: || strcmp(method, HTTP_METHOD_PUT) == 0
195: || strcmp(method, HTTP_METHOD_DELETE) == 0
196: || strcmp(method, HTTP_METHOD_TRACE) == 0) {
197: http_response_send_error(resp,
198: HTTP_STATUS_METHOD_NOT_ALLOWED, NULL);
199: return (-1);
200: } else {
201: http_response_send_error(resp,
202: HTTP_STATUS_NOT_IMPLEMENTED, NULL);
203: return (-1);
204: }
205:
206: /* If request was HEAD, omit sending the body */
207: if (strcasecmp(method, HTTP_METHOD_HEAD) == 0)
208: resp->msg->skip_body = 1;
209:
210: /* Check protocol is known */
211: if (strcmp(proto, HTTP_PROTO_0_9) != 0
212: && strcmp(proto, HTTP_PROTO_1_0) != 0
213: && strcmp(proto, HTTP_PROTO_1_1) != 0) {
214: http_response_send_error(resp,
215: HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED, NULL);
216: return (-1);
217: }
218:
219: /* If protocol is HTTP/0.9, don't send back any headers */
220: if (strcmp(proto, HTTP_PROTO_0_9) == 0)
221: resp->msg->no_headers = 1;
222:
223: /* Check for CONNECT method */
224: if (strcmp(method, HTTP_METHOD_CONNECT) == 0) {
225: if ((msg->host = STRDUP("http_message.host", uri)) == NULL)
226: goto malloc_fail;
227: conn->proxy = 1;
228: goto no_path;
229: }
230:
231: /* Get explicit scheme, if any */
232: colon = strchr(uri, ':');
233: slash = strchr(uri, '/');
234: if (colon != NULL && slash != NULL && colon < slash) {
235: char *c;
236:
237: strlcpy(scheme, uri, sizeof(scheme));
238: if ((c = strchr(scheme, ':')) != NULL)
239: *c = '\0';
240: conn->proxy = 1; /* explicit scheme => proxy request */
241: } else
242: strlcpy(scheme, "http", sizeof(scheme));
243:
244: /* We only support HTTP */
245: if (strcasecmp(scheme, "http") != 0) {
246: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
247: "Unsupported scheme \"%s\"", scheme);
248: return (-1);
249: }
250:
251: /* Separate out host, path and query parts from URI */
252: if (strncasecmp(uri, "http://", 7) == 0) {
253: if ((path = strchr(uri + 7, '/')) == NULL) {
254: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
255: "Request URI has no path component");
256: return (-1);
257: }
258: hlen = path - (uri + 7);
259: if ((msg->host = MALLOC("http_message.host", hlen + 1)) == NULL)
260: goto malloc_fail;
261: memcpy(msg->host, uri + 7, hlen);
262: msg->host[hlen] = '\0';
263: conn->proxy = 1;
264: } else if (*uri != '/') {
265: http_response_send_error(resp,
266: HTTP_STATUS_BAD_REQUEST, "Bogus non-absolute URI");
267: return (-1);
268: } else
269: path = uri;
270: if ((s = strchr(path, '?')) == NULL)
271: plen = strlen(path);
272: else {
273: plen = s - path;
274: if ((msg->query = STRDUP("http_message.query", s + 1)) == NULL)
275: goto malloc_fail;
276: }
277:
278: no_path:
279: /* Check body input length for POST, all others have no input body */
280: if (strcmp(method, HTTP_METHOD_POST) == 0) {
281: if (msg->input_len == UINT_MAX
282: && _http_head_want_keepalive(req->msg->head)) {
283: http_response_send_error(resp, HTTP_STATUS_BAD_REQUEST,
284: "Keep-Alive requires %s",
285: HTTP_HEADER_CONTENT_LENGTH);
286: return (-1);
287: }
288: } else
289: msg->input_len = 0; /* ignore C-L header */
290:
291: /* Decode URL path part */
292: if (path == NULL)
293: goto no_path2;
294: if ((msg->path = MALLOC("http_message.path", plen + 1)) == NULL) {
295: malloc_fail:
296: (*conn->logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
297: http_response_send_error(resp,
298: HTTP_STATUS_INTERNAL_SERVER_ERROR, "%s", strerror(errno));
299: return (-1);
300: }
301: memcpy(msg->path, path, plen);
302: msg->path[plen] = '\0';
303: http_request_url_decode(msg->path, msg->path);
304:
305: no_path2:
306: /* Check Host: header specified in a HTTP/1.1 request */
307: if (strcmp(proto, HTTP_PROTO_1_1) == 0
308: && msg->host == NULL
309: && _http_head_get(msg->head, HTTP_HEADER_HOST) == NULL) {
310: http_response_send_error(resp,
311: HTTP_STATUS_BAD_REQUEST, "No host specified");
312: return (-1);
313: }
314:
315: /* Decode name, value pairs from query string */
316: if (msg->query != NULL)
317: http_request_decode_query(req);
318:
319: /* Done */
320: return (0);
321: }
322:
323: /*
324: * Free a request structure.
325: */
326: void
327: _http_request_free(struct http_request **reqp)
328: {
329: struct http_request *const req = *reqp;
330: int i;
331:
332: if (req == NULL)
333: return;
334: _http_message_free(&req->msg);
335: FREE("http_request.username", req->username);
336: FREE("http_request.password", req->password);
337: for (i = 0; i < req->num_nvp; i++) {
338: struct http_nvp *const nvp = &req->nvp[i];
339:
340: FREE("http_request.nvp.name", nvp->name);
341: FREE("http_request.nvp.value", nvp->value);
342: }
343: FREE("http_request.nvp", req->nvp);
344: FREE("http_request", req);
345: *reqp = NULL;
346: }
347:
348: /*********************************************************************
349: MESSAGE WRAPPER ROUTINES
350: *********************************************************************/
351:
352: /*
353: * Get a request header.
354: *
355: * For headers listed multiple times, this only gets the first instance.
356: */
357: const char *
358: http_request_get_header(struct http_request *req, const char *name)
359: {
360: return (_http_head_get(req->msg->head, name));
361: }
362:
363: /*
364: * Get the number of headers
365: */
366: int
367: http_request_num_headers(struct http_request *req)
368: {
369: return (_http_head_num_headers(req->msg->head));
370: }
371:
372: /*
373: * Get header by index.
374: */
375: int
376: http_request_get_header_by_index(struct http_request *req,
377: u_int index, const char **namep, const char **valuep)
378: {
379: return (_http_head_get_by_index(req->msg->head, index, namep, valuep));
380: }
381:
382: /*
383: * Set a request header.
384: */
385: int
386: http_request_set_header(struct http_request *req, int append,
387: const char *name, const char *valfmt, ...)
388: {
389: va_list args;
390: int ret;
391:
392: /* Set header */
393: va_start(args, valfmt);
394: ret = _http_message_vset_header(req->msg, append, name, valfmt, args);
395: va_end(args);
396: return (ret);
397: }
398:
399: /*
400: * Remove a header.
401: */
402: int
403: http_request_remove_header(struct http_request *req, const char *name)
404: {
405: return (_http_message_remove_header(req->msg, name));
406: }
407:
408: /*
409: * Send request headers to peer.
410: */
411: int
412: http_request_send_headers(struct http_request *req)
413: {
414: const char *const method = http_request_get_method(req);
415: const char *const path = http_request_get_path(req);
416: const char *const uri = http_request_get_uri(req);
417: char *epath;
418:
419: /* Sanity checks */
420: if (req->msg->hdrs_sent)
421: return (0);
422: if (method == NULL || (path == NULL && uri == NULL)) {
423: errno = EINVAL;
424: return (-1);
425: }
426:
427: /* If request is GET, put name, value pairs in the query string */
428: if (strcmp(method, HTTP_METHOD_GET) == 0
429: && http_request_set_query_from_values(req) == -1)
430: return (-1);
431:
432: /* Set request URI */
433: if (uri == NULL) {
434: if ((epath = http_request_url_encode(
435: TYPED_MEM_TEMP, path)) == NULL)
436: return (-1);
437: if (http_request_set_header(req, 0,
438: HDR_REQUEST_URI, "%s%s%s", epath,
439: req->msg->query != NULL ? "?" : "",
440: req->msg->query != NULL ? req->msg->query : "") == -1) {
441: FREE(TYPED_MEM_TEMP, epath);
442: return (-1);
443: }
444: FREE(TYPED_MEM_TEMP, epath);
445: }
446:
447: /* Set other headers */
448: if (http_request_set_header(req, 0, HDR_REQUEST_METHOD,
449: "%s", http_request_get_method(req)) == -1)
450: return (-1);
451: if (http_request_set_header(req, 0, HDR_REQUEST_VERSION,
452: "%s", HTTP_PROTO_1_0) == -1)
453: return (-1);
454: if (http_request_set_header(req, 0,
455: _http_message_connection_header(req->msg), "%s",
456: req->msg->conn->keep_alive ? "Keep-Alive" : "Close") == -1)
457: return (-1);
458:
459: /* Send headers */
460: _http_message_send_headers(req->msg, 0);
461: return (0);
462: }
463:
464: /*
465: * Get the encoded query string.
466: */
467: const char *
468: http_request_get_query_string(struct http_request *req)
469: {
470: return (req->msg->query == NULL ? "" : req->msg->query);
471: }
472:
473: /*
474: * Get specified host, if any.
475: */
476: const char *
477: http_request_get_host(struct http_request *req)
478: {
479: struct http_connection *const conn = req->msg->conn;
480: const char *host;
481:
482: if (!conn->proxy
483: && (host = http_request_get_header(req, HTTP_HEADER_HOST)) != NULL)
484: return (host);
485: return (req->msg->host);
486: }
487:
488: /*
489: * Get query method.
490: */
491: const char *
492: http_request_get_method(struct http_request *req)
493: {
494: return (http_request_get_header(req, HDR_REQUEST_METHOD));
495: }
496:
497: /*
498: * Get query URI.
499: */
500: const char *
501: http_request_get_uri(struct http_request *req)
502: {
503: return (http_request_get_header(req, HDR_REQUEST_URI));
504: }
505:
506: /*
507: * Get query version.
508: */
509: const char *
510: http_request_get_version(struct http_request *req)
511: {
512: return (http_request_get_header(req, HDR_REQUEST_VERSION));
513: }
514:
515: /*
516: * Set query method.
517: */
518: int
519: http_request_set_method(struct http_request *req, const char *method)
520: {
521: /* Must be GET, POST, or HEAD for now */
522: if (strcmp(method, HTTP_METHOD_GET) != 0
523: && strcmp(method, HTTP_METHOD_POST) != 0
524: && strcmp(method, HTTP_METHOD_HEAD) != 0) {
525: errno = EINVAL;
526: return (-1);
527: }
528:
529: /* Set method */
530: if (http_request_set_header(req, 0,
531: HDR_REQUEST_METHOD, "%s", method) == -1)
532: return (-1);
533:
534: /* Only POST is allowed to have a body */
535: req->msg->no_body = (strcmp(method, HTTP_METHOD_POST) != 0);
536: return (0);
537: }
538:
539: /*
540: * Set proxy request bit.
541: */
542: void
543: http_request_set_proxy(struct http_request *req, int whether)
544: {
545: struct http_connection *const conn = req->msg->conn;
546:
547: conn->proxy = !!whether;
548: }
549:
550: /*
551: * Get the URL path.
552: */
553: const char *
554: http_request_get_path(struct http_request *req)
555: {
556: return (req->msg->path);
557: }
558:
559: /*
560: * Set the URL path.
561: */
562: int
563: http_request_set_path(struct http_request *req, const char *path)
564: {
565: char *copy;
566:
567: if (path == NULL || *path != '/') {
568: errno = EINVAL;
569: return (-1);
570: }
571: if ((copy = STRDUP("http_message.path", path)) == NULL)
572: return (-1);
573: FREE("http_message.path", req->msg->path);
574: req->msg->path = copy;
575: return (0);
576: }
577:
578: /*
579: * Get SSL context.
580: */
581: SSL_CTX *
582: http_request_get_ssl(struct http_request *req)
583: {
584: return (req->msg->conn->ssl);
585: }
586:
587: /*
588: * Get request input stream.
589: */
590: FILE *
591: http_request_get_input(struct http_request *req)
592: {
593: if (!req->msg->conn->server) {
594: errno = EINVAL;
595: return (NULL);
596: }
597: return (req->msg->input);
598: }
599:
600: /*
601: * Get raw i/o stream as a file descriptor.
602: */
603: int
604: http_request_get_raw_socket(struct http_request *req)
605: {
606: return (_http_message_get_raw_socket(req->msg));
607: }
608:
609: /*
610: * Get request output stream.
611: *
612: * If "buffer" is true, the entire output will be buffered unless
613: * the headers have already been sent.
614: */
615: FILE *
616: http_request_get_output(struct http_request *req, int buffer)
617: {
618: if (req->msg->conn->server) {
619: errno = EINVAL;
620: return (NULL);
621: }
622: return (_http_message_get_output(req->msg, buffer));
623: }
624:
625: /*
626: * Get remote IP address.
627: */
628: struct in_addr
629: http_request_get_remote_ip(struct http_request *req)
630: {
631: return (_http_message_get_remote_ip(req->msg));
632: }
633:
634: /*
635: * Get remote port.
636: */
637: u_int16_t
638: http_request_get_remote_port(struct http_request *req)
639: {
640: return (_http_message_get_remote_port(req->msg));
641: }
642:
643: /*********************************************************************
644: AUTHORIZATION ROUTINES
645: *********************************************************************/
646:
647: /*
648: * Get request remote username.
649: *
650: * Returns NULL if none specified.
651: */
652: const char *
653: http_request_get_username(struct http_request *req)
654: {
655: if (req->username == NULL)
656: http_request_decode_auth(req);
657: return (req->username);
658: }
659:
660: /*
661: * Get request remote password
662: *
663: * Returns NULL if none specified.
664: */
665: const char *
666: http_request_get_password(struct http_request *req)
667: {
668: if (req->password == NULL)
669: http_request_decode_auth(req);
670: return (req->password);
671: }
672:
673: /*
674: * Compute base64 encoded username and password, suitable for
675: * passing in a basic authentication header.
676: */
677: char *
678: http_request_encode_basic_auth(const char *mtype,
679: const char *username, const char *password)
680: {
681: char *buf;
682: char *auth;
683: int len;
684: int i, j;
685:
686: /* Get raw data buffer */
687: len = strlen(username) + 1 + strlen(password) + 1;
688: if ((buf = MALLOC(TYPED_MEM_TEMP, len)) == NULL)
689: return (NULL);
690: strcpy(buf, username);
691: strcat(buf, ":");
692: strcat(buf, password);
693:
694: /* Get encoded buffer */
695: len = (4 * len) / 3 + 32;
696: if ((auth = MALLOC(mtype, len)) == NULL) {
697: FREE(TYPED_MEM_TEMP, buf);
698: return (NULL);
699: }
700:
701: /* Encode bits */
702: len = strlen(buf);
703: for (j = i = 0; i < len; i += 3) {
704: const u_char b0 = ((u_char *)buf)[i];
705: const u_char b1 = (i < len - 1) ? ((u_char *)buf)[i + 1] : 0;
706: const u_char b2 = (i < len - 2) ? ((u_char *)buf)[i + 2] : 0;
707:
708: auth[j++] = base64[(b0 >> 2) & 0x3f];
709: auth[j++] = base64[((b0 << 4) & 0x30) | ((b1 >> 4) & 0x0f)];
710: if (i == len - 1)
711: break;
712: auth[j++] = base64[((b1 << 2) & 0x3c) | ((b2 >> 6) & 0x03)];
713: if (i == len - 2)
714: break;
715: auth[j++] = base64[b2 & 0x3f];
716: }
717: FREE(TYPED_MEM_TEMP, buf);
718:
719: /* Pad encoding to an even multiple with equals signs */
720: switch (len % 3) {
721: case 1: auth[j++] = '='; /* fall through */
722: case 2: auth[j++] = '=';
723: case 0: break;
724: }
725: auth[j] = '\0';
726:
727: /* Done */
728: return (auth);
729: }
730:
731: /*
732: * Decode basic Authorization: header.
733: */
734: static void
735: http_request_decode_auth(struct http_request *req)
736: {
737: static u_char table[256];
738: u_int val, pval = 0;
739: const char *s;
740: char buf[128];
741: char *pw;
1.1.1.2 ! misho 742: size_t len, step;
1.1 misho 743:
744: /* Initialize table (first time only) */
745: if (table[0] == 0) {
746: for (val = 0; val < 0x100; val++) {
747: table[val] = ((s = strchr(base64, (char)val)) != NULL) ?
748: s - base64 : 0xff;
749: }
750: }
751:
752: /* Get basic authentication header */
753: if ((s = http_request_get_header(req,
754: HTTP_HEADER_AUTHORIZATION)) == NULL
755: || strncmp(s, "Basic ", 6) != 0)
756: return;
757:
758: /* Decode it */
759: for (len = step = 0, s += 6; len < sizeof(buf) - 1 && *s != '\0'; s++) {
760:
761: /* Decode character */
762: if ((val = table[(u_char)*s]) == 0xff)
763: continue;
764:
765: /* Glom on bits */
766: switch (step % 4) {
767: case 1:
768: buf[len++] = (pval << 2) | ((val & 0x30) >> 4);
769: break;
770: case 2:
771: buf[len++] = ((pval & 0x0f) << 4) | ((val & 0x3c) >> 2);
772: break;
773: case 3:
774: buf[len++] = ((pval & 0x03) << 6) | val;
775: break;
776: }
777: pval = val;
778: step++;
779: }
780: buf[len] = '\0';
781:
782: /* Find password */
783: if ((pw = strchr(buf, ':')) == NULL)
784: return;
785: *pw++ = '\0';
786:
787: /* Allocate strings */
788: if ((req->username = STRDUP("http_request.username", buf)) == NULL)
789: return;
790: if ((req->password = STRDUP("http_request.password", pw)) == NULL) {
791: FREE("http_request.username", req->username);
792: req->username = NULL;
793: return;
794: }
795: }
796:
797: /*********************************************************************
798: FORM FILE UPLOAD
799: *********************************************************************/
800:
801: #define WHITESPACE " \t\r\n\f\v"
802:
803: struct upload_info {
804: const char *field;
805: FILE *fp;
806: int error;
807: size_t max;
808: };
809:
810: static http_mime_handler_t http_request_file_upload_handler;
811:
812: /*
813: * Read an HTTP POST containing MIME multipart data and write
814: * the contents of the named field into the supplied stream.
815: * The stream is NOT closed.
816: *
817: * If "max" is non-zero and more than "max" bytes are read,
818: * an error is returned with errno = EFBIG.
819: *
820: * Returns zero if successful, otherwise -1 and sets errno.
821: */
822: int
823: http_request_file_upload(struct http_request *req,
824: const char *field, FILE *fp, size_t max)
825: {
826: struct upload_info info;
827: const char *hval;
828: char *s;
829:
830: /* Verify proper submit was done */
831: if ((hval = http_request_get_header(req,
832: HTTP_HEADER_CONTENT_TYPE)) == NULL) {
833: errno = EINVAL;
834: return (-1);
835: }
836: if ((s = strchr(hval, ';')) == NULL
837: || strncasecmp(hval,
838: HTTP_CTYPE_MULTIPART_FORMDATA, s - hval) != 0) {
839: errno = EINVAL;
840: return (-1);
841: }
842:
843: /* Read form data into file */
844: memset(&info, 0, sizeof(info));
845: info.field = field;
846: info.fp = fp;
847: info.max = max;
848: if (http_request_get_mime_multiparts(req,
849: http_request_file_upload_handler, &info) < 0) {
850: if (info.error == 0)
851: info.error = errno;
852: }
853: if (info.error != 0) {
854: errno = info.error;
855: return (-1);
856: }
857:
858: /* Done */
859: return (0);
860: }
861:
862: static int
863: http_request_file_upload_handler(void *arg, struct mime_part *part, FILE *fp)
864: {
865: struct upload_info *const info = arg;
866: const char *hval = http_mime_part_get_header(part,
867: HTTP_HEADER_CONTENT_DISPOSITION);
868: char buf[256];
869: char *tokctx;
870: char *s, *t;
871: size_t len;
872: size_t nr;
873:
874: /* Parse content dispostion to get the field name */
875: strlcpy(buf, hval, sizeof(buf));
876: for (s = strtok_r(buf, WHITESPACE ";", &tokctx);
877: s != NULL;
878: s = strtok_r(NULL, WHITESPACE ";", &tokctx)) {
879: if (strncmp(s, "name=\"", 6) != 0)
880: continue;
881: s += 6;
882: if ((t = strchr(s, '"')) == NULL)
883: continue;
884: *t = '\0';
885: if (strcmp(s, info->field) == 0) /* is this the field? */
886: break;
887: }
888: if (s == NULL) /* wrong field */
889: return (0);
890:
891: /* Read data and write it to caller-supplied stream */
892: for (len = 0; (nr = fread(buf, 1, sizeof(buf), fp)) != 0; len += nr) {
893: if (info->max != 0 && len + nr > info->max) {
894: errno = EFBIG;
895: goto fail;
896: }
897: if (fwrite(buf, 1, nr, info->fp) != nr)
898: goto fail;
899: }
900: if (ferror(fp)) {
901: fail: info->error = errno;
902: return (-1);
903: }
904:
905: /* Done */
906: return (0);
907: }
908:
909: /*********************************************************************
910: NAME VALUE PAIR ROUTINES
911: *********************************************************************/
912:
913: /*
914: * Get a value from a request.
915: */
916: const char *
917: http_request_get_value(struct http_request *req, const char *name, int instance)
918: {
1.1.1.2 ! misho 919: struct const_http_nvp key;
1.1 misho 920: struct http_nvp *nvp;
921:
1.1.1.2 ! misho 922: key.name = name;
1.1 misho 923: if ((nvp = bsearch(&key,
924: req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp)) == NULL)
925: return (NULL);
926: while (instance-- > 0) {
927: if (++nvp - req->nvp >= req->num_nvp
928: || strcmp(nvp->name, name) != 0)
929: return (NULL);
930: }
931: return (nvp->value);
932: }
933:
934: /*
935: * Set a value associated with a query.
936: */
937: int
938: http_request_set_value(struct http_request *req,
939: const char *name, const char *value)
940: {
941: int ret;
942:
943: if ((ret = http_request_add_nvp(req, 0, name, value)) == -1)
944: return (-1);
945: mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp);
946: return (0);
947: }
948:
949: /*
950: * Get the number of NVP's.
951: */
952: int
953: http_request_get_num_values(struct http_request *req)
954: {
955: return (req->num_nvp);
956: }
957:
958: /*
959: * Get the name of an NVP by index.
960: */
961: int
962: http_request_get_value_by_index(struct http_request *req, int i,
963: const char **name, const char **value)
964: {
965: if (i < 0 || i >= req->num_nvp) {
966: errno = EINVAL;
967: return (-1);
968: }
969: if (name != NULL)
970: *name = req->nvp[i].name;
971: if (value != NULL)
972: *value = req->nvp[i].value;
973: return (0);
974: }
975:
976: /*
977: * Reset the query string from the list of name, value pairs.
978: */
979: int
980: http_request_set_query_from_values(struct http_request *req)
981: {
982: char *buf;
983: int qlen;
984: int i;
985:
986: /* If no values, no query string */
987: if (req->num_nvp == 0) {
988: buf = NULL;
989: goto done;
990: }
991:
992: /* Get bound on encoded query string length */
993: for (qlen = i = 0; i < req->num_nvp; i++) {
994: const struct http_nvp *const nvp = &req->nvp[i];
995:
996: qlen += strlen(nvp->name) * 3 + 1 + strlen(nvp->value) * 3;
997: }
998:
999: /* Allocate new buffer */
1000: if ((buf = MALLOC("http_message.query", qlen + 1)) == NULL)
1001: return (-1);
1002:
1003: /* Encode name, value pairs into buffer */
1004: for (qlen = i = 0; i < req->num_nvp; i++) {
1005: const struct http_nvp *const nvp = &req->nvp[i];
1006: char *ename;
1007: char *evalue;
1008:
1009: if ((ename = http_request_url_encode(TYPED_MEM_TEMP,
1010: nvp->name)) == NULL) {
1011: FREE("http_message.query", buf);
1012: return (-1);
1013: }
1014: if ((evalue = http_request_url_encode(TYPED_MEM_TEMP,
1015: nvp->value)) == NULL) {
1016: FREE(TYPED_MEM_TEMP, ename);
1017: FREE("http_message.query", buf);
1018: return (-1);
1019: }
1020: qlen += sprintf(buf + qlen, "%s%s=%s",
1021: i > 0 ? "&" : "", ename, evalue);
1022: FREE(TYPED_MEM_TEMP, ename);
1023: FREE(TYPED_MEM_TEMP, evalue);
1024: }
1025:
1026: done:
1027: /* Set new query string */
1028: FREE("http_message.query", req->msg->query);
1029: req->msg->query = buf;
1030: return (0);
1031: }
1032:
1033: /*
1034: * Read in name, value pairs as URL-encoded form data.
1035: * Typically this is used for receiving POST requests.
1036: */
1037: int
1038: http_request_read_url_encoded_values(struct http_request *req)
1039: {
1040: FILE *input;
1041: char *name;
1042: char *value;
1043: int count;
1044: int totlen;
1045: int ret;
1046: int ch;
1047:
1048: /* Get input stream */
1049: if ((input = http_request_get_input(req)) == NULL)
1050: return (-1);
1051:
1052: /* Read in URL-encoded name, value pairs */
1053: for (count = totlen = 0; totlen < MAX_NVP_DATA; totlen++) {
1054:
1055: /* Read name */
1056: if ((name = read_string_until(TYPED_MEM_TEMP,
1057: req->msg->input, "&=")) == NULL)
1058: return (-1);
1059:
1060: /* Read value, if any */
1061: if ((ch = getc(req->msg->input)) == '=') {
1062: if ((value = read_string_until(TYPED_MEM_TEMP,
1063: req->msg->input, "&")) == NULL) {
1064: FREE(TYPED_MEM_TEMP, name);
1065: return (-1);
1066: }
1067: } else
1068: value = NULL;
1069:
1070: /* Slurp next char */
1071: (void)getc(req->msg->input);
1072:
1073: /* Add name, value pair */
1074: ret = 0;
1075: if (*name != '\0') {
1076: ret = http_request_add_nvp(req, 1,
1077: name, (value != NULL) ? value : "");
1078: count++;
1079: }
1080: FREE(TYPED_MEM_TEMP, name);
1081: FREE(TYPED_MEM_TEMP, value);
1082: if (ret == -1)
1083: return (-1);
1084: }
1085:
1086: /* Sort name using mergesort() which preserves order of duplicates */
1087: if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1)
1088: return (-1);
1089:
1090: /* Done */
1091: return (count);
1092: }
1093:
1094: /*
1095: * Write out name, value pairs as URL-encoded form data.
1096: * Typically this is used for sending POST requests.
1097: */
1098: int
1099: http_request_write_url_encoded_values(struct http_request *req)
1100: {
1101: int i;
1102:
1103: /* Get output stream */
1104: if (req->msg->output == NULL) {
1105: errno = EINVAL;
1106: return (-1);
1107: }
1108:
1109: /* Encode name, value pairs into buffer */
1110: for (i = 0; i < req->num_nvp; i++) {
1111: const struct http_nvp *const nvp = &req->nvp[i];
1112: char *ename;
1113: char *evalue;
1114:
1115: if ((ename = http_request_url_encode(TYPED_MEM_TEMP,
1116: nvp->name)) == NULL)
1117: return (-1);
1118: if ((evalue = http_request_url_encode(TYPED_MEM_TEMP,
1119: nvp->value)) == NULL) {
1120: FREE(TYPED_MEM_TEMP, ename);
1121: return (-1);
1122: }
1123: fprintf(req->msg->output, "%s%s=%s",
1124: i > 0 ? "&" : "", ename, evalue);
1125: FREE(TYPED_MEM_TEMP, ename);
1126: FREE(TYPED_MEM_TEMP, evalue);
1127: }
1128: return (0);
1129: }
1130:
1131: /*
1132: * Parse out query string into name, value pairs.
1133: */
1134: static int
1135: http_request_decode_query(struct http_request *req)
1136: {
1137: char *tokctx;
1138: char *qbuf;
1139: char *name;
1140: char *value;
1141:
1142: /* Sanity */
1143: if (req->msg->query == NULL)
1144: return (0);
1145:
1146: /* Copy original encoded query string */
1147: if ((qbuf = STRDUP(TYPED_MEM_TEMP, req->msg->query)) == NULL)
1148: return (-1);
1149:
1150: /* Separate out and decode name, value pairs */
1151: for (name = strtok_r(qbuf, "&", &tokctx);
1152: name != NULL;
1153: name = strtok_r(NULL, "&", &tokctx)) {
1154:
1155: /* Find value */
1156: if ((value = strchr(name, '=')) == NULL)
1157: continue;
1158: *value++ = '\0';
1159:
1160: /* Add name, value pair */
1161: if (http_request_add_nvp(req, 1, name, value) == -1) {
1162: FREE(TYPED_MEM_TEMP, qbuf);
1163: return (-1);
1164: }
1165: }
1166: FREE(TYPED_MEM_TEMP, qbuf);
1167:
1168: /* Sort name using mergesort() which preserves order of duplicates */
1169: if (mergesort(req->nvp, req->num_nvp, sizeof(*req->nvp), nvp_cmp) == -1)
1170: return (-1);
1171: return (0);
1172: }
1173:
1174: /*
1175: * Add an (optionally URL-encoded) name, value pair.
1176: *
1177: * Array must be sorted again by caller.
1178: */
1179: static int
1180: http_request_add_nvp(struct http_request *req, int encoded,
1181: const char *ename, const char *evalue)
1182: {
1183: char *name;
1184: char *value;
1185: void *mem;
1186:
1187: /* Create buffers */
1188: if ((name = MALLOC("http_request.nvp.name", strlen(ename) + 1)) == NULL)
1189: return (-1);
1190: if ((value = MALLOC("http_request.nvp.value",
1191: strlen(evalue) + 1)) == NULL) {
1192: FREE("http_request.nvp.name", name);
1193: return (-1);
1194: }
1195:
1196: /* URL-decode name and value */
1197: if (encoded) {
1198: http_request_url_decode(ename, name);
1199: http_request_url_decode(evalue, value);
1200: } else {
1201: strcpy(name, ename);
1202: strcpy(value, evalue);
1203: }
1204:
1205: /* Add new pointer struct */
1206: if ((mem = REALLOC("http_request.nvp", req->nvp,
1207: (req->num_nvp + 1) * sizeof(*req->nvp))) == NULL) {
1208: FREE("http_request.nvp.name", name);
1209: FREE("http_request.nvp.value", value);
1210: return (-1);
1211: }
1212: req->nvp = mem;
1213: req->nvp[req->num_nvp].name = name;
1214: req->nvp[req->num_nvp].value = value;
1215: req->num_nvp++;
1216: return (0);
1217: }
1218:
1219: /*
1220: * Comparator for name, value pairs
1221: */
1222: static int
1223: nvp_cmp(const void *v1, const void *v2)
1224: {
1225: const struct http_nvp *const q1 = v1;
1226: const struct http_nvp *const q2 = v2;
1227:
1228: return (strcmp(q1->name, q2->name));
1229: }
1230:
1231: /*
1232: * Read a string until a terminating character or EOF is seen.
1233: */
1234: static char *
1235: read_string_until(const char *mtype, FILE *fp, const char *term)
1236: {
1237: size_t alloc = 32;
1238: void *mem;
1239: char *s;
1.1.1.2 ! misho 1240: size_t len = 0;
1.1 misho 1241: int ch;
1242:
1243: if ((s = MALLOC(mtype, alloc)) == NULL)
1244: return (NULL);
1245: while (len < MAX_NVP_LEN) {
1246: if ((ch = getc(fp)) == EOF) {
1247: s[len] = '\0';
1248: return (s);
1249: }
1250: if (strchr(term, ch) != NULL && ch != '\0') {
1251: ungetc(ch, fp);
1252: s[len] = '\0';
1253: return (s);
1254: }
1255: s[len++] = ch;
1256: if (len == alloc) {
1257: alloc <<= 1;
1258: if ((mem = REALLOC(mtype, s, alloc)) == NULL)
1259: goto fail;
1260: s = mem;
1261: }
1262: }
1263: errno = E2BIG;
1264: fail:
1265: FREE(mtype, s);
1266: return (NULL);
1267: }
1268:
1269: /*********************************************************************
1270: MISC ROUTINES
1271: *********************************************************************/
1272:
1273: /*
1274: * URL-encode a string.
1275: */
1276: char *
1277: http_request_url_encode(const char *mtype, const char *s)
1278: {
1279: char *enc;
1280: char *t;
1281:
1282: if ((enc = MALLOC(mtype, (strlen(s) * 3) + 1)) == NULL)
1283: return (NULL);
1284: for (t = enc; *s != '\0'; s++) {
1285: if (!isalnum((u_char)*s) && strchr("-_.!~*'()/:", *s) == NULL)
1286: t += sprintf(t, "%%%02x", (u_char)*s);
1287: else
1288: *t++ = *s;
1289: }
1290: *t = '\0';
1291: return (enc);
1292: }
1293:
1294: /*
1295: * URL-decode a string.
1296: */
1297: void
1298: http_request_url_decode(const char *s, char *t)
1299: {
1300: for (; *s != '\0'; s++, t++) {
1301: switch (s[0]) {
1302: case '+':
1303: *t = ' ';
1304: break;
1305: case '%':
1306: if (isxdigit((u_char)s[1]) && isxdigit((u_char)s[2])) {
1307: *t = isdigit((u_char)s[1]) ?
1308: s[1] - '0' : tolower(s[1]) - 'a' + 10;
1309: *t <<= 4;
1310: *t |= isdigit((u_char)s[2]) ?
1311: s[2] - '0' : tolower(s[2]) - 'a' + 10;
1312: s += 2;
1313: break;
1314: }
1315: /* fall through */
1316: default:
1317: *t = *s;
1318: break;
1319: }
1320: }
1321: *t = '\0';
1322: }
1323:
1324: /*
1325: * Parse an HTTP time string.
1326: *
1327: * Returns (time_t)-1 if there was an error.
1328: */
1329: time_t
1330: http_request_parse_time(const char *string)
1331: {
1332: static const char *fmts[] = {
1333: HTTP_TIME_FMT_RFC1123,
1334: HTTP_TIME_FMT_RFC850,
1335: HTTP_TIME_FMT_CTIME,
1336: };
1337: struct tm whentm;
1338: time_t when;
1.1.1.2 ! misho 1339: unsigned i;
1.1 misho 1340:
1341: for (i = 0; i < sizeof(fmts) / sizeof(*fmts); i++) {
1342: memset(&whentm, 0, sizeof(whentm));
1343: if (strptime(string, fmts[i], &whentm) != NULL
1344: && (when = timegm(&whentm)) != (time_t)-1)
1345: return (when);
1346: }
1347: return ((time_t)-1);
1348: }
1349:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>