Annotation of embedaddon/mpd/src/contrib/libpdel/http/http_message.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 <pthread.h>
51: #include <limits.h>
52: #include <syslog.h>
53: #include <errno.h>
54: #include <ctype.h>
55:
56: #include <openssl/ssl.h>
57:
58: #include "structs/structs.h"
59: #include "structs/type/array.h"
60:
61: #include "util/typed_mem.h"
62: #include "http/http_defs.h"
63: #include "http/http_server.h"
64: #include "http/http_internal.h"
65:
66: /*
67: * Internal functions
68: */
69: static int http_message_input_read(void *cookie, char *buf, int len);
70: static int http_message_input_close(void *cookie);
71: static int http_message_output_write(void *cookie,
72: const char *buf, int len);
73: static int http_message_output_close(void *cookie);
74:
75: /*********************************************************************
76: MAIN ROUTINES
77: *********************************************************************/
78:
79: /*
80: * Create a new message structure.
81: */
82: struct http_message *
83: _http_message_new(void)
84: {
85: struct http_message *msg;
86:
87: if ((msg = MALLOC("http_message", sizeof(*msg))) == NULL)
88: return (NULL);
89: memset(msg, 0, sizeof(*msg));
90: if ((msg->head = _http_head_new()) == NULL) {
91: FREE("http_message", msg);
92: return (NULL);
93: }
94: return (msg);
95: }
96:
97: /*
98: * Initialize a message by loading in HTTP headers from a stream,
99: * and set msg->input to be the entity input stream.
100: *
101: * This reads any Content-Length header and sets msg->input_len
102: * accordingly, or UINT_MAX if none found. Messages that by definition
103: * have no body must reset msg->input_len to zero.
104: */
105: int
106: _http_message_read(struct http_message *msg, int req)
107: {
108: struct http_connection *const conn = msg->conn;
109: const char *s;
110:
111: /* Slurp in HTTP headers */
112: if (_http_head_read(msg->head, conn->fp, req) == -1)
113: return (-1);
114:
115: /* Get content length, if any */
116: msg->input_len = UINT_MAX;
117: if ((s = _http_head_get(msg->head,
118: HTTP_HEADER_CONTENT_LENGTH)) != NULL) {
119: if (sscanf(s, "%u", &msg->input_len) != 1) {
120: errno = EINVAL;
121: return (-1);
122: }
123: }
124:
125: /* Create input stream */
126: if ((msg->input = funopen(msg, http_message_input_read,
127: NULL, NULL, http_message_input_close)) == NULL)
128: return (-1);
129:
130: /* Debugging */
131: if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) {
132: DBG(HTTP_HDRS, "dumping %s headers:",
133: msg->conn->server ? "REQUEST" : "RESPONSE");
134: _http_head_write(msg->head, stdout);
135: }
136:
137: /* Done */
138: return (0);
139: }
140:
141: /*
142: * Free a message structure.
143: */
144: void
145: _http_message_free(struct http_message **msgp)
146: {
147: struct http_message *const msg = *msgp;
148:
149: if (msg == NULL)
150: return;
151: _http_head_free(&msg->head);
152: if (msg->input != NULL)
153: fclose(msg->input);
154: if (msg->output != NULL)
155: fclose(msg->output);
156: if (msg->output_buf != NULL)
157: FREE("http_message.output_buf", msg->output_buf);
158: FREE("http_message.query", msg->query);
159: FREE("http_message.host", msg->host);
160: FREE("http_message.path", msg->path);
161: FREE("http_message", msg);
162: *msgp = NULL;
163: }
164:
165: /*
166: * Get message output stream.
167: *
168: * If "buffer" is true, the entire output will be buffered unless
169: * the headers have already been sent.
170: */
171: FILE *
172: _http_message_get_output(struct http_message *msg, int buffer)
173: {
174: if (msg->output == NULL) {
175: if ((msg->output = funopen(msg, NULL,
176: http_message_output_write, NULL,
177: http_message_output_close)) == NULL)
178: return (NULL);
179: msg->buffered = buffer;
180: }
181: return (msg->output);
182: }
183:
184: /*
185: * Get raw i/o stream as a file descriptor.
186: */
187: int
188: _http_message_get_raw_socket(struct http_message *msg)
189: {
190: if (msg->conn->ssl != NULL) {
191: errno = EPROTOTYPE;
192: return (-1);
193: }
194: return (msg->conn->sock);
195: }
196:
197: /*
198: * Send message headers, if not sent already.
199: */
200: void
201: _http_message_send_headers(struct http_message *msg, int unbuffer)
202: {
203: /* Do nothing if nothing to do */
204: if (msg->hdrs_sent)
205: return;
206:
207: /* If we're unbuffering message, turn off buffered flag */
208: if (!msg->buffered)
209: unbuffer = 0;
210: else if (unbuffer) {
211: if (msg->output != NULL)
212: fflush(msg->output);
213: msg->buffered = 0;
214: }
215:
216: /* In buffered mode, set Content-Length header from buffer length.
217: In non-buffed mode, turn off connection keep-alive. If no body,
218: remove content related headers. */
219: if (msg->no_body) {
220: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_ENCODING);
221: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_LENGTH);
222: _http_head_remove(msg->head, HTTP_HEADER_CONTENT_TYPE);
223: _http_head_remove(msg->head, HTTP_HEADER_LAST_MODIFIED);
224: } else if (msg->buffered) {
225: if (msg->output != NULL)
226: fflush(msg->output);
227: _http_head_set(msg->head, 0, HTTP_HEADER_CONTENT_LENGTH,
228: "%u", msg->output_len);
229: } else if (_http_head_get(msg->head,
230: HTTP_HEADER_CONTENT_LENGTH) == NULL) {
231: _http_head_set(msg->head, 0,
232: _http_message_connection_header(msg), "Close");
233: }
234:
235: /* Debugging */
236: if (PDEL_DEBUG_ENABLED(HTTP_HDRS)) {
237: DBG(HTTP_HDRS, "dumping %s headers:",
238: msg->conn->server ? "RESPONSE" : "REQUEST");
239: _http_head_write(msg->head, stdout);
240: }
241:
242: /* Send headers */
243: if (!msg->no_headers)
244: _http_head_write(msg->head, msg->conn->fp);
245: msg->hdrs_sent = 1;
246:
247: /* If unbuffering, send and release any output buffered so far */
248: if (unbuffer) {
249: _http_message_send_body(msg);
250: FREE("http_message.output_buf", msg->output_buf);
251: msg->output_buf = NULL;
252: msg->output_len = 0;
253: }
254: }
255:
256: /*
257: * Send message body.
258: */
259: void
260: _http_message_send_body(struct http_message *msg)
261: {
262: struct http_connection *const conn = msg->conn;
263:
264: /* Flush output stream data */
265: if (msg->output != NULL)
266: fflush(msg->output);
267:
268: /* Send buffered output (if it was buffered) */
269: if (msg->output_buf != NULL) {
270: if (!msg->skip_body)
271: fwrite(msg->output_buf, 1, msg->output_len, conn->fp);
272: fflush(conn->fp);
273: }
274: }
275:
276: /*
277: * Set a message header.
278: */
279: int
280: _http_message_vset_header(struct http_message *msg, int append,
281: const char *name, const char *valfmt, va_list args)
282: {
283:
284: /* Check if we already sent the headers */
285: if (msg->hdrs_sent) {
286: errno = EALREADY;
287: return (-1);
288: }
289:
290: /* Set header */
291: return (_http_head_vset(msg->head, append, name, valfmt, args));
292: }
293:
294: /*
295: * Remove a message header.
296: */
297: int
298: _http_message_remove_header(struct http_message *msg, const char *name)
299: {
300: return (_http_head_remove(msg->head, name));
301: }
302:
303: /*
304: * Get the "Connection" header name, which will be either "Connection"
305: * or "Proxy-Connection".
306: */
307: const char *
308: _http_message_connection_header(struct http_message *msg)
309: {
310: struct http_connection *const conn = msg->conn;
311: const char *hval;
312:
313: if (!conn->proxy
314: || (hval = _http_head_get(msg->head, conn->server ?
315: HDR_REQUEST_VERSION : HDR_REPLY_VERSION)) == NULL
316: || strcmp(hval, HTTP_PROTO_1_1) >= 0)
317: return (HTTP_HEADER_CONNECTION);
318: return (HTTP_HEADER_PROXY_CONNECTION);
319: }
320:
321: /*
322: * Get remote IP address.
323: */
324: struct in_addr
325: _http_message_get_remote_ip(struct http_message *msg)
326: {
327: return (msg->conn->remote_ip);
328: }
329:
330: /*
331: * Get remote port.
332: */
333: u_int16_t
334: _http_message_get_remote_port(struct http_message *msg)
335: {
336: return (msg->conn->remote_port);
337: }
338:
339: /*
340: * Figure out whether anything is in the message at all.
341: */
342: int
343: _http_message_has_anything(struct http_message *msg)
344: {
345: return (_http_head_has_anything(msg->head));
346: }
347:
348: /*********************************************************************
349: INPUT STREAM METHODS
350: *********************************************************************/
351:
352: /*
353: * Read message input stream.
354: */
355: static int
356: http_message_input_read(void *cookie, char *buf, int len)
357: {
358: struct http_message *const msg = cookie;
359: int ret;
360:
361: if (msg->input_read == msg->input_len || len < 0)
362: return (0);
1.1.1.2 ! misho 363: if ((unsigned)len > msg->input_len - msg->input_read)
1.1 misho 364: len = msg->input_len - msg->input_read;
365: if ((ret = fread(buf, 1, len, msg->conn->fp)) != len) {
366: if (ferror(msg->conn->fp))
367: return (-1);
368: }
369: msg->input_read += ret;
370: return (ret);
371: }
372:
373: /*
374: * Close message input stream.
375: */
376: static int
377: http_message_input_close(void *cookie)
378: {
379: struct http_message *const msg = cookie;
380:
381: msg->input = NULL;
382: return (0);
383: }
384:
385: /*********************************************************************
386: OUTPUT STREAM METHODS
387: *********************************************************************/
388:
389: /*
390: * Write to message output stream.
391: */
392: static int
393: http_message_output_write(void *cookie, const char *buf, int len)
394: {
395: struct http_message *const msg = cookie;
396: struct http_connection *const conn = msg->conn;
397: int totlen;
398: int ret;
399: void *mem;
400:
401: /* Ignore zero length writes */
402: if (len == 0)
403: return (0);
404:
405: /* Check whether to allow an entity body at all */
406: if (msg->no_body) {
407: errno = EINVAL;
408: return (-1);
409: }
410:
411: /* If not buffered, check if headers have been sent then write data */
412: if (!msg->buffered) {
413: if (!msg->hdrs_sent)
414: _http_message_send_headers(msg, 0);
415: if (msg->skip_body)
416: return (len);
417: if ((ret = fwrite(buf, 1, len, conn->fp)) != len)
418: return (-1);
419: return (ret);
420: }
421:
422: /* Expand buffer and write data into it */
423: totlen = msg->output_len + len;
424: if ((mem = REALLOC("http_message.output_buf",
425: msg->output_buf, totlen)) == NULL) {
426: (*conn->logger)(LOG_ERR, "%s: %s", "realloc", strerror(errno));
427: return (-1);
428: }
429: msg->output_buf = mem;
430: memcpy(msg->output_buf + msg->output_len, buf, len);
431: msg->output_len += len;
432: return (len);
433: }
434:
435: /*
436: * Close message output stream.
437: */
438: static int
439: http_message_output_close(void *cookie)
440: {
441: struct http_message *const msg = cookie;
442:
443: msg->output = NULL;
444: return (0);
445: }
446:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>