|
|
1.1 root 1: /*
2: * Copyright (C) 2007 Michael Brown <[email protected]>.
3: *
4: * This program is free software; you can redistribute it and/or
5: * modify it under the terms of the GNU General Public License as
6: * published by the Free Software Foundation; either version 2 of the
7: * License, or any later version.
8: *
9: * This program is distributed in the hope that it will be useful, but
10: * WITHOUT ANY WARRANTY; without even the implied warranty of
11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12: * General Public License for more details.
13: *
14: * You should have received a copy of the GNU General Public License
15: * along with this program; if not, write to the Free Software
16: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: FILE_LICENCE ( GPL2_OR_LATER );
20:
21: /**
22: * @file
23: *
24: * Hyper Text Transfer Protocol (HTTP)
25: *
26: */
27:
28: #include <stdint.h>
29: #include <stdlib.h>
30: #include <stdio.h>
31: #include <string.h>
32: #include <strings.h>
33: #include <byteswap.h>
34: #include <errno.h>
35: #include <assert.h>
36: #include <ipxe/uri.h>
37: #include <ipxe/refcnt.h>
38: #include <ipxe/iobuf.h>
39: #include <ipxe/xfer.h>
40: #include <ipxe/open.h>
41: #include <ipxe/socket.h>
42: #include <ipxe/tcpip.h>
43: #include <ipxe/process.h>
44: #include <ipxe/linebuf.h>
45: #include <ipxe/features.h>
46: #include <ipxe/base64.h>
47: #include <ipxe/http.h>
48:
49: FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
50:
51: /** HTTP receive state */
52: enum http_rx_state {
53: HTTP_RX_RESPONSE = 0,
54: HTTP_RX_HEADER,
55: HTTP_RX_DATA,
56: HTTP_RX_DEAD,
57: };
58:
59: /**
60: * An HTTP request
61: *
62: */
63: struct http_request {
64: /** Reference count */
65: struct refcnt refcnt;
66: /** Data transfer interface */
67: struct interface xfer;
68:
69: /** URI being fetched */
70: struct uri *uri;
71: /** Transport layer interface */
72: struct interface socket;
73:
74: /** TX process */
75: struct process process;
76:
77: /** HTTP response code */
78: unsigned int response;
79: /** HTTP Content-Length */
80: size_t content_length;
81: /** Received length */
82: size_t rx_len;
83: /** RX state */
84: enum http_rx_state rx_state;
85: /** Line buffer for received header lines */
86: struct line_buffer linebuf;
87: };
88:
89: /**
90: * Free HTTP request
91: *
92: * @v refcnt Reference counter
93: */
94: static void http_free ( struct refcnt *refcnt ) {
95: struct http_request *http =
96: container_of ( refcnt, struct http_request, refcnt );
97:
98: uri_put ( http->uri );
99: empty_line_buffer ( &http->linebuf );
100: free ( http );
101: };
102:
103: /**
104: * Mark HTTP request as complete
105: *
106: * @v http HTTP request
107: * @v rc Return status code
108: */
109: static void http_done ( struct http_request *http, int rc ) {
110:
111: /* Prevent further processing of any current packet */
112: http->rx_state = HTTP_RX_DEAD;
113:
114: /* If we had a Content-Length, and the received content length
115: * isn't correct, flag an error
116: */
117: if ( http->content_length &&
118: ( http->content_length != http->rx_len ) ) {
119: DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
120: http, http->rx_len, http->content_length );
121: rc = -EIO;
122: }
123:
124: /* Remove process */
125: process_del ( &http->process );
126:
127: /* Close all data transfer interfaces */
128: intf_shutdown ( &http->socket, rc );
129: intf_shutdown ( &http->xfer, rc );
130: }
131:
132: /**
133: * Convert HTTP response code to return status code
134: *
135: * @v response HTTP response code
136: * @ret rc Return status code
137: */
138: static int http_response_to_rc ( unsigned int response ) {
139: switch ( response ) {
140: case 200:
141: case 301:
142: case 302:
143: return 0;
144: case 404:
145: return -ENOENT;
146: case 403:
147: return -EPERM;
148: case 401:
149: return -EACCES;
150: default:
151: return -EIO;
152: }
153: }
154:
155: /**
156: * Handle HTTP response
157: *
158: * @v http HTTP request
159: * @v response HTTP response
160: * @ret rc Return status code
161: */
162: static int http_rx_response ( struct http_request *http, char *response ) {
163: char *spc;
164: int rc;
165:
166: DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
167:
168: /* Check response starts with "HTTP/" */
169: if ( strncmp ( response, "HTTP/", 5 ) != 0 )
170: return -EIO;
171:
172: /* Locate and check response code */
173: spc = strchr ( response, ' ' );
174: if ( ! spc )
175: return -EIO;
176: http->response = strtoul ( spc, NULL, 10 );
177: if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
178: return rc;
179:
180: /* Move to received headers */
181: http->rx_state = HTTP_RX_HEADER;
182: return 0;
183: }
184:
185: /**
186: * Handle HTTP Location header
187: *
188: * @v http HTTP request
189: * @v value HTTP header value
190: * @ret rc Return status code
191: */
192: static int http_rx_location ( struct http_request *http, const char *value ) {
193: int rc;
194:
195: /* Redirect to new location */
196: DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
197: if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
198: value ) ) != 0 ) {
199: DBGC ( http, "HTTP %p could not redirect: %s\n",
200: http, strerror ( rc ) );
201: return rc;
202: }
203:
204: return 0;
205: }
206:
207: /**
208: * Handle HTTP Content-Length header
209: *
210: * @v http HTTP request
211: * @v value HTTP header value
212: * @ret rc Return status code
213: */
214: static int http_rx_content_length ( struct http_request *http,
215: const char *value ) {
216: char *endp;
217:
218: http->content_length = strtoul ( value, &endp, 10 );
219: if ( *endp != '\0' ) {
220: DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
221: http, value );
222: return -EIO;
223: }
224:
225: /* Use seek() to notify recipient of filesize */
226: xfer_seek ( &http->xfer, http->content_length );
227: xfer_seek ( &http->xfer, 0 );
228:
229: return 0;
230: }
231:
232: /** An HTTP header handler */
233: struct http_header_handler {
234: /** Name (e.g. "Content-Length") */
235: const char *header;
236: /** Handle received header
237: *
238: * @v http HTTP request
239: * @v value HTTP header value
240: * @ret rc Return status code
241: *
242: * If an error is returned, the download will be aborted.
243: */
244: int ( * rx ) ( struct http_request *http, const char *value );
245: };
246:
247: /** List of HTTP header handlers */
248: static struct http_header_handler http_header_handlers[] = {
249: {
250: .header = "Location",
251: .rx = http_rx_location,
252: },
253: {
254: .header = "Content-Length",
255: .rx = http_rx_content_length,
256: },
257: { NULL, NULL }
258: };
259:
260: /**
261: * Handle HTTP header
262: *
263: * @v http HTTP request
264: * @v header HTTP header
265: * @ret rc Return status code
266: */
267: static int http_rx_header ( struct http_request *http, char *header ) {
268: struct http_header_handler *handler;
269: char *separator;
270: char *value;
271: int rc;
272:
273: /* An empty header line marks the transition to the data phase */
274: if ( ! header[0] ) {
275: DBGC ( http, "HTTP %p start of data\n", http );
276: empty_line_buffer ( &http->linebuf );
277: http->rx_state = HTTP_RX_DATA;
278: return 0;
279: }
280:
281: DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
282:
283: /* Split header at the ": " */
284: separator = strstr ( header, ": " );
285: if ( ! separator ) {
286: DBGC ( http, "HTTP %p malformed header\n", http );
287: return -EIO;
288: }
289: *separator = '\0';
290: value = ( separator + 2 );
291:
292: /* Hand off to header handler, if one exists */
293: for ( handler = http_header_handlers ; handler->header ; handler++ ) {
294: if ( strcasecmp ( header, handler->header ) == 0 ) {
295: if ( ( rc = handler->rx ( http, value ) ) != 0 )
296: return rc;
297: break;
298: }
299: }
300: return 0;
301: }
302:
303: /** An HTTP line-based data handler */
304: struct http_line_handler {
305: /** Handle line
306: *
307: * @v http HTTP request
308: * @v line Line to handle
309: * @ret rc Return status code
310: */
311: int ( * rx ) ( struct http_request *http, char *line );
312: };
313:
314: /** List of HTTP line-based data handlers */
315: static struct http_line_handler http_line_handlers[] = {
316: [HTTP_RX_RESPONSE] = { .rx = http_rx_response },
317: [HTTP_RX_HEADER] = { .rx = http_rx_header },
318: };
319:
320: /**
321: * Handle new data arriving via HTTP connection in the data phase
322: *
323: * @v http HTTP request
324: * @v iobuf I/O buffer
325: * @ret rc Return status code
326: */
327: static int http_rx_data ( struct http_request *http,
328: struct io_buffer *iobuf ) {
329: int rc;
330:
331: /* Update received length */
332: http->rx_len += iob_len ( iobuf );
333:
334: /* Hand off data buffer */
335: if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
336: return rc;
337:
338: /* If we have reached the content-length, stop now */
339: if ( http->content_length &&
340: ( http->rx_len >= http->content_length ) ) {
341: http_done ( http, 0 );
342: }
343:
344: return 0;
345: }
346:
347: /**
348: * Handle new data arriving via HTTP connection
349: *
350: * @v http HTTP request
351: * @v iobuf I/O buffer
352: * @v meta Data transfer metadata
353: * @ret rc Return status code
354: */
355: static int http_socket_deliver ( struct http_request *http,
356: struct io_buffer *iobuf,
357: struct xfer_metadata *meta __unused ) {
358: struct http_line_handler *lh;
359: char *line;
360: ssize_t len;
361: int rc = 0;
362:
363: while ( iob_len ( iobuf ) ) {
364: switch ( http->rx_state ) {
365: case HTTP_RX_DEAD:
366: /* Do no further processing */
367: goto done;
368: case HTTP_RX_DATA:
369: /* Once we're into the data phase, just fill
370: * the data buffer
371: */
372: rc = http_rx_data ( http, iob_disown ( iobuf ) );
373: goto done;
374: case HTTP_RX_RESPONSE:
375: case HTTP_RX_HEADER:
376: /* In the other phases, buffer and process a
377: * line at a time
378: */
379: len = line_buffer ( &http->linebuf, iobuf->data,
380: iob_len ( iobuf ) );
381: if ( len < 0 ) {
382: rc = len;
383: DBGC ( http, "HTTP %p could not buffer line: "
384: "%s\n", http, strerror ( rc ) );
385: goto done;
386: }
387: iob_pull ( iobuf, len );
388: line = buffered_line ( &http->linebuf );
389: if ( line ) {
390: lh = &http_line_handlers[http->rx_state];
391: if ( ( rc = lh->rx ( http, line ) ) != 0 )
392: goto done;
393: }
394: break;
395: default:
396: assert ( 0 );
397: break;
398: }
399: }
400:
401: done:
402: if ( rc )
403: http_done ( http, rc );
404: free_iob ( iobuf );
405: return rc;
406: }
407:
408: /**
409: * HTTP process
410: *
411: * @v process Process
412: */
413: static void http_step ( struct process *process ) {
414: struct http_request *http =
415: container_of ( process, struct http_request, process );
416: const char *host = http->uri->host;
417: const char *user = http->uri->user;
418: const char *password =
419: ( http->uri->password ? http->uri->password : "" );
420: size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
421: strlen ( password ) ) : 0 );
422: size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
423: uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
424: char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
425: int rc;
426: int request_len = unparse_uri ( NULL, 0, http->uri,
427: URI_PATH_BIT | URI_QUERY_BIT );
428:
429: if ( xfer_window ( &http->socket ) ) {
430: char request[request_len + 1];
431:
432: /* Construct path?query request */
433: unparse_uri ( request, sizeof ( request ), http->uri,
434: URI_PATH_BIT | URI_QUERY_BIT );
435:
436: /* We want to execute only once */
437: process_del ( &http->process );
438:
439: /* Construct authorisation, if applicable */
440: if ( user ) {
441: /* Make "user:password" string from decoded fields */
442: snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
443: "%s:%s", user, password );
444:
445: /* Base64-encode the "user:password" string */
446: base64_encode ( user_pw, user_pw_len, user_pw_base64 );
447: }
448:
449: /* Send GET request */
450: if ( ( rc = xfer_printf ( &http->socket,
451: "GET %s%s HTTP/1.0\r\n"
452: "User-Agent: iPXE/" VERSION "\r\n"
453: "%s%s%s"
454: "Host: %s\r\n"
455: "\r\n",
456: http->uri->path ? "" : "/",
457: request,
458: ( user ?
459: "Authorization: Basic " : "" ),
460: ( user ? user_pw_base64 : "" ),
461: ( user ? "\r\n" : "" ),
462: host ) ) != 0 ) {
463: http_done ( http, rc );
464: }
465: }
466: }
467:
468: /** HTTP socket interface operations */
469: static struct interface_operation http_socket_operations[] = {
470: INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
471: INTF_OP ( intf_close, struct http_request *, http_done ),
472: };
473:
474: /** HTTP socket interface descriptor */
475: static struct interface_descriptor http_socket_desc =
476: INTF_DESC_PASSTHRU ( struct http_request, socket,
477: http_socket_operations, xfer );
478:
479: /** HTTP data transfer interface operations */
480: static struct interface_operation http_xfer_operations[] = {
481: INTF_OP ( intf_close, struct http_request *, http_done ),
482: };
483:
484: /** HTTP data transfer interface descriptor */
485: static struct interface_descriptor http_xfer_desc =
486: INTF_DESC_PASSTHRU ( struct http_request, xfer,
487: http_xfer_operations, socket );
488:
489: /**
490: * Initiate an HTTP connection, with optional filter
491: *
492: * @v xfer Data transfer interface
493: * @v uri Uniform Resource Identifier
494: * @v default_port Default port number
495: * @v filter Filter to apply to socket, or NULL
496: * @ret rc Return status code
497: */
498: int http_open_filter ( struct interface *xfer, struct uri *uri,
499: unsigned int default_port,
500: int ( * filter ) ( struct interface *xfer,
501: struct interface **next ) ) {
502: struct http_request *http;
503: struct sockaddr_tcpip server;
504: struct interface *socket;
505: int rc;
506:
507: /* Sanity checks */
508: if ( ! uri->host )
509: return -EINVAL;
510:
511: /* Allocate and populate HTTP structure */
512: http = zalloc ( sizeof ( *http ) );
513: if ( ! http )
514: return -ENOMEM;
515: ref_init ( &http->refcnt, http_free );
516: intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
517: http->uri = uri_get ( uri );
518: intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
519: process_init ( &http->process, http_step, &http->refcnt );
520:
521: /* Open socket */
522: memset ( &server, 0, sizeof ( server ) );
523: server.st_port = htons ( uri_port ( http->uri, default_port ) );
524: socket = &http->socket;
525: if ( filter ) {
526: if ( ( rc = filter ( socket, &socket ) ) != 0 )
527: goto err;
528: }
529: if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
530: ( struct sockaddr * ) &server,
531: uri->host, NULL ) ) != 0 )
532: goto err;
533:
534: /* Attach to parent interface, mortalise self, and return */
535: intf_plug_plug ( &http->xfer, xfer );
536: ref_put ( &http->refcnt );
537: return 0;
538:
539: err:
540: DBGC ( http, "HTTP %p could not create request: %s\n",
541: http, strerror ( rc ) );
542: http_done ( http, rc );
543: ref_put ( &http->refcnt );
544: return rc;
545: }
546:
547: /**
548: * Initiate an HTTP connection
549: *
550: * @v xfer Data transfer interface
551: * @v uri Uniform Resource Identifier
552: * @ret rc Return status code
553: */
554: static int http_open ( struct interface *xfer, struct uri *uri ) {
555: return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
556: }
557:
558: /** HTTP URI opener */
559: struct uri_opener http_uri_opener __uri_opener = {
560: .scheme = "http",
561: .open = http_open,
562: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.