Home | History | Annotate | Download | only in tcp
      1 /*
      2  * Copyright (C) 2007 Michael Brown <mbrown (at) fensystems.co.uk>.
      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 <gpxe/uri.h>
     37 #include <gpxe/refcnt.h>
     38 #include <gpxe/iobuf.h>
     39 #include <gpxe/xfer.h>
     40 #include <gpxe/open.h>
     41 #include <gpxe/socket.h>
     42 #include <gpxe/tcpip.h>
     43 #include <gpxe/process.h>
     44 #include <gpxe/linebuf.h>
     45 #include <gpxe/features.h>
     46 #include <gpxe/base64.h>
     47 #include <gpxe/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 xfer_interface xfer;
     68 
     69 	/** URI being fetched */
     70 	struct uri *uri;
     71 	/** Transport layer interface */
     72 	struct xfer_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 	xfer_nullify ( &http->socket );
    129 	xfer_close ( &http->socket, rc );
    130 	xfer_nullify ( &http->xfer );
    131 	xfer_close ( &http->xfer, rc );
    132 }
    133 
    134 /**
    135  * Convert HTTP response code to return status code
    136  *
    137  * @v response		HTTP response code
    138  * @ret rc		Return status code
    139  */
    140 static int http_response_to_rc ( unsigned int response ) {
    141 	switch ( response ) {
    142 	case 200:
    143 	case 301:
    144 	case 302:
    145 		return 0;
    146 	case 404:
    147 		return -ENOENT;
    148 	case 403:
    149 		return -EPERM;
    150 	case 401:
    151 		return -EACCES;
    152 	default:
    153 		return -EIO;
    154 	}
    155 }
    156 
    157 /**
    158  * Handle HTTP response
    159  *
    160  * @v http		HTTP request
    161  * @v response		HTTP response
    162  * @ret rc		Return status code
    163  */
    164 static int http_rx_response ( struct http_request *http, char *response ) {
    165 	char *spc;
    166 	int rc;
    167 
    168 	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
    169 
    170 	/* Check response starts with "HTTP/" */
    171 	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
    172 		return -EIO;
    173 
    174 	/* Locate and check response code */
    175 	spc = strchr ( response, ' ' );
    176 	if ( ! spc )
    177 		return -EIO;
    178 	http->response = strtoul ( spc, NULL, 10 );
    179 	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
    180 		return rc;
    181 
    182 	/* Move to received headers */
    183 	http->rx_state = HTTP_RX_HEADER;
    184 	return 0;
    185 }
    186 
    187 /**
    188  * Handle HTTP Location header
    189  *
    190  * @v http		HTTP request
    191  * @v value		HTTP header value
    192  * @ret rc		Return status code
    193  */
    194 static int http_rx_location ( struct http_request *http, const char *value ) {
    195 	int rc;
    196 
    197 	/* Redirect to new location */
    198 	DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
    199 	if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
    200 				    value ) ) != 0 ) {
    201 		DBGC ( http, "HTTP %p could not redirect: %s\n",
    202 		       http, strerror ( rc ) );
    203 		return rc;
    204 	}
    205 
    206 	return 0;
    207 }
    208 
    209 /**
    210  * Handle HTTP Content-Length header
    211  *
    212  * @v http		HTTP request
    213  * @v value		HTTP header value
    214  * @ret rc		Return status code
    215  */
    216 static int http_rx_content_length ( struct http_request *http,
    217 				    const char *value ) {
    218 	char *endp;
    219 
    220 	http->content_length = strtoul ( value, &endp, 10 );
    221 	if ( *endp != '\0' ) {
    222 		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
    223 		       http, value );
    224 		return -EIO;
    225 	}
    226 
    227 	/* Use seek() to notify recipient of filesize */
    228 	xfer_seek ( &http->xfer, http->content_length, SEEK_SET );
    229 	xfer_seek ( &http->xfer, 0, SEEK_SET );
    230 
    231 	return 0;
    232 }
    233 
    234 /** An HTTP header handler */
    235 struct http_header_handler {
    236 	/** Name (e.g. "Content-Length") */
    237 	const char *header;
    238 	/** Handle received header
    239 	 *
    240 	 * @v http	HTTP request
    241 	 * @v value	HTTP header value
    242 	 * @ret rc	Return status code
    243 	 *
    244 	 * If an error is returned, the download will be aborted.
    245 	 */
    246 	int ( * rx ) ( struct http_request *http, const char *value );
    247 };
    248 
    249 /** List of HTTP header handlers */
    250 static struct http_header_handler http_header_handlers[] = {
    251 	{
    252 		.header = "Location",
    253 		.rx = http_rx_location,
    254 	},
    255 	{
    256 		.header = "Content-Length",
    257 		.rx = http_rx_content_length,
    258 	},
    259 	{ NULL, NULL }
    260 };
    261 
    262 /**
    263  * Handle HTTP header
    264  *
    265  * @v http		HTTP request
    266  * @v header		HTTP header
    267  * @ret rc		Return status code
    268  */
    269 static int http_rx_header ( struct http_request *http, char *header ) {
    270 	struct http_header_handler *handler;
    271 	char *separator;
    272 	char *value;
    273 	int rc;
    274 
    275 	/* An empty header line marks the transition to the data phase */
    276 	if ( ! header[0] ) {
    277 		DBGC ( http, "HTTP %p start of data\n", http );
    278 		empty_line_buffer ( &http->linebuf );
    279 		http->rx_state = HTTP_RX_DATA;
    280 		return 0;
    281 	}
    282 
    283 	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
    284 
    285 	/* Split header at the ": " */
    286 	separator = strstr ( header, ": " );
    287 	if ( ! separator ) {
    288 		DBGC ( http, "HTTP %p malformed header\n", http );
    289 		return -EIO;
    290 	}
    291 	*separator = '\0';
    292 	value = ( separator + 2 );
    293 
    294 	/* Hand off to header handler, if one exists */
    295 	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
    296 		if ( strcasecmp ( header, handler->header ) == 0 ) {
    297 			if ( ( rc = handler->rx ( http, value ) ) != 0 )
    298 				return rc;
    299 			break;
    300 		}
    301 	}
    302 	return 0;
    303 }
    304 
    305 /** An HTTP line-based data handler */
    306 struct http_line_handler {
    307 	/** Handle line
    308 	 *
    309 	 * @v http	HTTP request
    310 	 * @v line	Line to handle
    311 	 * @ret rc	Return status code
    312 	 */
    313 	int ( * rx ) ( struct http_request *http, char *line );
    314 };
    315 
    316 /** List of HTTP line-based data handlers */
    317 static struct http_line_handler http_line_handlers[] = {
    318 	[HTTP_RX_RESPONSE]	= { .rx = http_rx_response },
    319 	[HTTP_RX_HEADER]	= { .rx = http_rx_header },
    320 };
    321 
    322 /**
    323  * Handle new data arriving via HTTP connection in the data phase
    324  *
    325  * @v http		HTTP request
    326  * @v iobuf		I/O buffer
    327  * @ret rc		Return status code
    328  */
    329 static int http_rx_data ( struct http_request *http,
    330 			  struct io_buffer *iobuf ) {
    331 	int rc;
    332 
    333 	/* Update received length */
    334 	http->rx_len += iob_len ( iobuf );
    335 
    336 	/* Hand off data buffer */
    337 	if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
    338 		return rc;
    339 
    340 	/* If we have reached the content-length, stop now */
    341 	if ( http->content_length &&
    342 	     ( http->rx_len >= http->content_length ) ) {
    343 		http_done ( http, 0 );
    344 	}
    345 
    346 	return 0;
    347 }
    348 
    349 /**
    350  * Handle new data arriving via HTTP connection
    351  *
    352  * @v socket		Transport layer interface
    353  * @v iobuf		I/O buffer
    354  * @v meta		Data transfer metadata
    355  * @ret rc		Return status code
    356  */
    357 static int http_socket_deliver_iob ( struct xfer_interface *socket,
    358 				     struct io_buffer *iobuf,
    359 				     struct xfer_metadata *meta __unused ) {
    360 	struct http_request *http =
    361 		container_of ( socket, struct http_request, socket );
    362 	struct http_line_handler *lh;
    363 	char *line;
    364 	ssize_t len;
    365 	int rc = 0;
    366 
    367 	while ( iob_len ( iobuf ) ) {
    368 		switch ( http->rx_state ) {
    369 		case HTTP_RX_DEAD:
    370 			/* Do no further processing */
    371 			goto done;
    372 		case HTTP_RX_DATA:
    373 			/* Once we're into the data phase, just fill
    374 			 * the data buffer
    375 			 */
    376 			rc = http_rx_data ( http, iob_disown ( iobuf ) );
    377 			goto done;
    378 		case HTTP_RX_RESPONSE:
    379 		case HTTP_RX_HEADER:
    380 			/* In the other phases, buffer and process a
    381 			 * line at a time
    382 			 */
    383 			len = line_buffer ( &http->linebuf, iobuf->data,
    384 					    iob_len ( iobuf ) );
    385 			if ( len < 0 ) {
    386 				rc = len;
    387 				DBGC ( http, "HTTP %p could not buffer line: "
    388 				       "%s\n", http, strerror ( rc ) );
    389 				goto done;
    390 			}
    391 			iob_pull ( iobuf, len );
    392 			line = buffered_line ( &http->linebuf );
    393 			if ( line ) {
    394 				lh = &http_line_handlers[http->rx_state];
    395 				if ( ( rc = lh->rx ( http, line ) ) != 0 )
    396 					goto done;
    397 			}
    398 			break;
    399 		default:
    400 			assert ( 0 );
    401 			break;
    402 		}
    403 	}
    404 
    405  done:
    406 	if ( rc )
    407 		http_done ( http, rc );
    408 	free_iob ( iobuf );
    409 	return rc;
    410 }
    411 
    412 /**
    413  * HTTP process
    414  *
    415  * @v process		Process
    416  */
    417 static void http_step ( struct process *process ) {
    418 	struct http_request *http =
    419 		container_of ( process, struct http_request, process );
    420 	const char *host = http->uri->host;
    421 	const char *user = http->uri->user;
    422 	const char *password =
    423 		( http->uri->password ? http->uri->password : "" );
    424 	size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
    425 					strlen ( password ) ) : 0 );
    426 	size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
    427 	char user_pw[ user_pw_len + 1 /* NUL */ ];
    428 	char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
    429 	int rc;
    430 	int request_len = unparse_uri ( NULL, 0, http->uri,
    431 					URI_PATH_BIT | URI_QUERY_BIT );
    432 
    433 	if ( xfer_window ( &http->socket ) ) {
    434 		char request[request_len + 1];
    435 
    436 		/* Construct path?query request */
    437 		unparse_uri ( request, sizeof ( request ), http->uri,
    438 			      URI_PATH_BIT | URI_QUERY_BIT );
    439 
    440 		/* We want to execute only once */
    441 		process_del ( &http->process );
    442 
    443 		/* Construct authorisation, if applicable */
    444 		if ( user ) {
    445 			/* Make "user:password" string from decoded fields */
    446 			snprintf ( user_pw, sizeof ( user_pw ), "%s:%s",
    447 				   user, password );
    448 
    449 			/* Base64-encode the "user:password" string */
    450 			base64_encode ( user_pw, user_pw_base64 );
    451 		}
    452 
    453 		/* Send GET request */
    454 		if ( ( rc = xfer_printf ( &http->socket,
    455 					  "GET %s%s HTTP/1.0\r\n"
    456 					  "User-Agent: gPXE/" VERSION "\r\n"
    457 					  "%s%s%s"
    458 					  "Host: %s\r\n"
    459 					  "\r\n",
    460 					  http->uri->path ? "" : "/",
    461 					  request,
    462 					  ( user ?
    463 					    "Authorization: Basic " : "" ),
    464 					  ( user ? user_pw_base64 : "" ),
    465 					  ( user ? "\r\n" : "" ),
    466 					  host ) ) != 0 ) {
    467 			http_done ( http, rc );
    468 		}
    469 	}
    470 }
    471 
    472 /**
    473  * HTTP connection closed by network stack
    474  *
    475  * @v socket		Transport layer interface
    476  * @v rc		Reason for close
    477  */
    478 static void http_socket_close ( struct xfer_interface *socket, int rc ) {
    479 	struct http_request *http =
    480 		container_of ( socket, struct http_request, socket );
    481 
    482 	DBGC ( http, "HTTP %p socket closed: %s\n",
    483 	       http, strerror ( rc ) );
    484 
    485 	http_done ( http, rc );
    486 }
    487 
    488 /** HTTP socket operations */
    489 static struct xfer_interface_operations http_socket_operations = {
    490 	.close		= http_socket_close,
    491 	.vredirect	= xfer_vreopen,
    492 	.window		= unlimited_xfer_window,
    493 	.alloc_iob	= default_xfer_alloc_iob,
    494 	.deliver_iob	= http_socket_deliver_iob,
    495 	.deliver_raw	= xfer_deliver_as_iob,
    496 };
    497 
    498 /**
    499  * Close HTTP data transfer interface
    500  *
    501  * @v xfer		Data transfer interface
    502  * @v rc		Reason for close
    503  */
    504 static void http_xfer_close ( struct xfer_interface *xfer, int rc ) {
    505 	struct http_request *http =
    506 		container_of ( xfer, struct http_request, xfer );
    507 
    508 	DBGC ( http, "HTTP %p interface closed: %s\n",
    509 	       http, strerror ( rc ) );
    510 
    511 	http_done ( http, rc );
    512 }
    513 
    514 /** HTTP data transfer interface operations */
    515 static struct xfer_interface_operations http_xfer_operations = {
    516 	.close		= http_xfer_close,
    517 	.vredirect	= ignore_xfer_vredirect,
    518 	.window		= unlimited_xfer_window,
    519 	.alloc_iob	= default_xfer_alloc_iob,
    520 	.deliver_iob	= xfer_deliver_as_raw,
    521 	.deliver_raw	= ignore_xfer_deliver_raw,
    522 };
    523 
    524 /**
    525  * Initiate an HTTP connection, with optional filter
    526  *
    527  * @v xfer		Data transfer interface
    528  * @v uri		Uniform Resource Identifier
    529  * @v default_port	Default port number
    530  * @v filter		Filter to apply to socket, or NULL
    531  * @ret rc		Return status code
    532  */
    533 int http_open_filter ( struct xfer_interface *xfer, struct uri *uri,
    534 		       unsigned int default_port,
    535 		       int ( * filter ) ( struct xfer_interface *xfer,
    536 					  struct xfer_interface **next ) ) {
    537 	struct http_request *http;
    538 	struct sockaddr_tcpip server;
    539 	struct xfer_interface *socket;
    540 	int rc;
    541 
    542 	/* Sanity checks */
    543 	if ( ! uri->host )
    544 		return -EINVAL;
    545 
    546 	/* Allocate and populate HTTP structure */
    547 	http = zalloc ( sizeof ( *http ) );
    548 	if ( ! http )
    549 		return -ENOMEM;
    550 	http->refcnt.free = http_free;
    551 	xfer_init ( &http->xfer, &http_xfer_operations, &http->refcnt );
    552        	http->uri = uri_get ( uri );
    553 	xfer_init ( &http->socket, &http_socket_operations, &http->refcnt );
    554 	process_init ( &http->process, http_step, &http->refcnt );
    555 
    556 	/* Open socket */
    557 	memset ( &server, 0, sizeof ( server ) );
    558 	server.st_port = htons ( uri_port ( http->uri, default_port ) );
    559 	socket = &http->socket;
    560 	if ( filter ) {
    561 		if ( ( rc = filter ( socket, &socket ) ) != 0 )
    562 			goto err;
    563 	}
    564 	if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
    565 					     ( struct sockaddr * ) &server,
    566 					     uri->host, NULL ) ) != 0 )
    567 		goto err;
    568 
    569 	/* Attach to parent interface, mortalise self, and return */
    570 	xfer_plug_plug ( &http->xfer, xfer );
    571 	ref_put ( &http->refcnt );
    572 	return 0;
    573 
    574  err:
    575 	DBGC ( http, "HTTP %p could not create request: %s\n",
    576 	       http, strerror ( rc ) );
    577 	http_done ( http, rc );
    578 	ref_put ( &http->refcnt );
    579 	return rc;
    580 }
    581 
    582 /**
    583  * Initiate an HTTP connection
    584  *
    585  * @v xfer		Data transfer interface
    586  * @v uri		Uniform Resource Identifier
    587  * @ret rc		Return status code
    588  */
    589 static int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
    590 	return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
    591 }
    592 
    593 /** HTTP URI opener */
    594 struct uri_opener http_uri_opener __uri_opener = {
    595 	.scheme	= "http",
    596 	.open	= http_open,
    597 };
    598