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