00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <stdint.h>
00029 #include <stdlib.h>
00030 #include <stdio.h>
00031 #include <string.h>
00032 #include <strings.h>
00033 #include <byteswap.h>
00034 #include <errno.h>
00035 #include <assert.h>
00036 #include <gpxe/uri.h>
00037 #include <gpxe/refcnt.h>
00038 #include <gpxe/iobuf.h>
00039 #include <gpxe/xfer.h>
00040 #include <gpxe/open.h>
00041 #include <gpxe/socket.h>
00042 #include <gpxe/tcpip.h>
00043 #include <gpxe/process.h>
00044 #include <gpxe/linebuf.h>
00045 #include <gpxe/features.h>
00046 #include <gpxe/base64.h>
00047 #include <gpxe/http.h>
00048
00049 FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
00050
00051
00052 enum http_rx_state {
00053 HTTP_RX_RESPONSE = 0,
00054 HTTP_RX_HEADER,
00055 HTTP_RX_DATA,
00056 HTTP_RX_DEAD,
00057 };
00058
00059
00060
00061
00062
00063 struct http_request {
00064
00065 struct refcnt refcnt;
00066
00067 struct xfer_interface xfer;
00068
00069
00070 struct uri *uri;
00071
00072 struct xfer_interface socket;
00073
00074
00075 struct process process;
00076
00077
00078 unsigned int response;
00079
00080 size_t content_length;
00081
00082 size_t rx_len;
00083
00084 enum http_rx_state rx_state;
00085
00086 struct line_buffer linebuf;
00087 };
00088
00089
00090
00091
00092
00093
00094 static void http_free ( struct refcnt *refcnt ) {
00095 struct http_request *http =
00096 container_of ( refcnt, struct http_request, refcnt );
00097
00098 uri_put ( http->uri );
00099 empty_line_buffer ( &http->linebuf );
00100 free ( http );
00101 };
00102
00103
00104
00105
00106
00107
00108
00109 static void http_done ( struct http_request *http, int rc ) {
00110
00111
00112 http->rx_state = HTTP_RX_DEAD;
00113
00114
00115
00116
00117 if ( http->content_length &&
00118 ( http->content_length != http->rx_len ) ) {
00119 DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
00120 http, http->rx_len, http->content_length );
00121 rc = -EIO;
00122 }
00123
00124
00125 process_del ( &http->process );
00126
00127
00128 xfer_nullify ( &http->socket );
00129 xfer_close ( &http->socket, rc );
00130 xfer_nullify ( &http->xfer );
00131 xfer_close ( &http->xfer, rc );
00132 }
00133
00134
00135
00136
00137
00138
00139
00140 static int http_response_to_rc ( unsigned int response ) {
00141 switch ( response ) {
00142 case 200:
00143 case 301:
00144 case 302:
00145 return 0;
00146 case 404:
00147 return -ENOENT;
00148 case 403:
00149 return -EPERM;
00150 case 401:
00151 return -EACCES;
00152 default:
00153 return -EIO;
00154 }
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164 static int http_rx_response ( struct http_request *http, char *response ) {
00165 char *spc;
00166 int rc;
00167
00168 DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
00169
00170
00171 if ( strncmp ( response, "HTTP/", 5 ) != 0 )
00172 return -EIO;
00173
00174
00175 spc = strchr ( response, ' ' );
00176 if ( ! spc )
00177 return -EIO;
00178 http->response = strtoul ( spc, NULL, 10 );
00179 if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
00180 return rc;
00181
00182
00183 http->rx_state = HTTP_RX_HEADER;
00184 return 0;
00185 }
00186
00187
00188
00189
00190
00191
00192
00193
00194 static int http_rx_location ( struct http_request *http, const char *value ) {
00195 int rc;
00196
00197
00198 DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
00199 if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
00200 value ) ) != 0 ) {
00201 DBGC ( http, "HTTP %p could not redirect: %s\n",
00202 http, strerror ( rc ) );
00203 return rc;
00204 }
00205
00206 return 0;
00207 }
00208
00209
00210
00211
00212
00213
00214
00215
00216 static int http_rx_content_length ( struct http_request *http,
00217 const char *value ) {
00218 char *endp;
00219
00220 http->content_length = strtoul ( value, &endp, 10 );
00221 if ( *endp != '\0' ) {
00222 DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
00223 http, value );
00224 return -EIO;
00225 }
00226
00227
00228 xfer_seek ( &http->xfer, http->content_length, SEEK_SET );
00229 xfer_seek ( &http->xfer, 0, SEEK_SET );
00230
00231 return 0;
00232 }
00233
00234
00235 struct http_header_handler {
00236
00237 const char *header;
00238
00239
00240
00241
00242
00243
00244
00245
00246 int ( * rx ) ( struct http_request *http, const char *value );
00247 };
00248
00249
00250 static struct http_header_handler http_header_handlers[] = {
00251 {
00252 .header = "Location",
00253 .rx = http_rx_location,
00254 },
00255 {
00256 .header = "Content-Length",
00257 .rx = http_rx_content_length,
00258 },
00259 { NULL, NULL }
00260 };
00261
00262
00263
00264
00265
00266
00267
00268
00269 static int http_rx_header ( struct http_request *http, char *header ) {
00270 struct http_header_handler *handler;
00271 char *separator;
00272 char *value;
00273 int rc;
00274
00275
00276 if ( ! header[0] ) {
00277 DBGC ( http, "HTTP %p start of data\n", http );
00278 empty_line_buffer ( &http->linebuf );
00279 http->rx_state = HTTP_RX_DATA;
00280 return 0;
00281 }
00282
00283 DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
00284
00285
00286 separator = strstr ( header, ": " );
00287 if ( ! separator ) {
00288 DBGC ( http, "HTTP %p malformed header\n", http );
00289 return -EIO;
00290 }
00291 *separator = '\0';
00292 value = ( separator + 2 );
00293
00294
00295 for ( handler = http_header_handlers ; handler->header ; handler++ ) {
00296 if ( strcasecmp ( header, handler->header ) == 0 ) {
00297 if ( ( rc = handler->rx ( http, value ) ) != 0 )
00298 return rc;
00299 break;
00300 }
00301 }
00302 return 0;
00303 }
00304
00305
00306 struct http_line_handler {
00307
00308
00309
00310
00311
00312
00313 int ( * rx ) ( struct http_request *http, char *line );
00314 };
00315
00316
00317 static struct http_line_handler http_line_handlers[] = {
00318 [HTTP_RX_RESPONSE] = { .rx = http_rx_response },
00319 [HTTP_RX_HEADER] = { .rx = http_rx_header },
00320 };
00321
00322
00323
00324
00325
00326
00327
00328
00329 static int http_rx_data ( struct http_request *http,
00330 struct io_buffer *iobuf ) {
00331 int rc;
00332
00333
00334 http->rx_len += iob_len ( iobuf );
00335
00336
00337 if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
00338 return rc;
00339
00340
00341 if ( http->content_length &&
00342 ( http->rx_len >= http->content_length ) ) {
00343 http_done ( http, 0 );
00344 }
00345
00346 return 0;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357 static int http_socket_deliver_iob ( struct xfer_interface *socket,
00358 struct io_buffer *iobuf,
00359 struct xfer_metadata *meta __unused ) {
00360 struct http_request *http =
00361 container_of ( socket, struct http_request, socket );
00362 struct http_line_handler *lh;
00363 char *line;
00364 ssize_t len;
00365 int rc = 0;
00366
00367 while ( iob_len ( iobuf ) ) {
00368 switch ( http->rx_state ) {
00369 case HTTP_RX_DEAD:
00370
00371 goto done;
00372 case HTTP_RX_DATA:
00373
00374
00375
00376 rc = http_rx_data ( http, iob_disown ( iobuf ) );
00377 goto done;
00378 case HTTP_RX_RESPONSE:
00379 case HTTP_RX_HEADER:
00380
00381
00382
00383 len = line_buffer ( &http->linebuf, iobuf->data,
00384 iob_len ( iobuf ) );
00385 if ( len < 0 ) {
00386 rc = len;
00387 DBGC ( http, "HTTP %p could not buffer line: "
00388 "%s\n", http, strerror ( rc ) );
00389 goto done;
00390 }
00391 iob_pull ( iobuf, len );
00392 line = buffered_line ( &http->linebuf );
00393 if ( line ) {
00394 lh = &http_line_handlers[http->rx_state];
00395 if ( ( rc = lh->rx ( http, line ) ) != 0 )
00396 goto done;
00397 }
00398 break;
00399 default:
00400 assert ( 0 );
00401 break;
00402 }
00403 }
00404
00405 done:
00406 if ( rc )
00407 http_done ( http, rc );
00408 free_iob ( iobuf );
00409 return rc;
00410 }
00411
00412
00413
00414
00415
00416
00417 static void http_step ( struct process *process ) {
00418 struct http_request *http =
00419 container_of ( process, struct http_request, process );
00420 const char *host = http->uri->host;
00421 const char *user = http->uri->user;
00422 const char *password =
00423 ( http->uri->password ? http->uri->password : "" );
00424 size_t user_pw_len = ( user ? ( strlen ( user ) + 1 +
00425 strlen ( password ) ) : 0 );
00426 size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
00427 char user_pw[ user_pw_len + 1 ];
00428 char user_pw_base64[ user_pw_base64_len + 1 ];
00429 int rc;
00430 int request_len = unparse_uri ( NULL, 0, http->uri,
00431 URI_PATH_BIT | URI_QUERY_BIT );
00432
00433 if ( xfer_window ( &http->socket ) ) {
00434 char request[request_len + 1];
00435
00436
00437 unparse_uri ( request, sizeof ( request ), http->uri,
00438 URI_PATH_BIT | URI_QUERY_BIT );
00439
00440
00441 process_del ( &http->process );
00442
00443
00444 if ( user ) {
00445
00446 snprintf ( user_pw, sizeof ( user_pw ), "%s:%s",
00447 user, password );
00448
00449
00450 base64_encode ( user_pw, user_pw_base64 );
00451 }
00452
00453
00454 if ( ( rc = xfer_printf ( &http->socket,
00455 "GET %s%s HTTP/1.0\r\n"
00456 "User-Agent: gPXE/" VERSION "\r\n"
00457 "%s%s%s"
00458 "Host: %s\r\n"
00459 "\r\n",
00460 http->uri->path ? "" : "/",
00461 request,
00462 ( user ?
00463 "Authorization: Basic " : "" ),
00464 ( user ? user_pw_base64 : "" ),
00465 ( user ? "\r\n" : "" ),
00466 host ) ) != 0 ) {
00467 http_done ( http, rc );
00468 }
00469 }
00470 }
00471
00472
00473
00474
00475
00476
00477
00478 static void http_socket_close ( struct xfer_interface *socket, int rc ) {
00479 struct http_request *http =
00480 container_of ( socket, struct http_request, socket );
00481
00482 DBGC ( http, "HTTP %p socket closed: %s\n",
00483 http, strerror ( rc ) );
00484
00485 http_done ( http, rc );
00486 }
00487
00488
00489 static struct xfer_interface_operations http_socket_operations = {
00490 .close = http_socket_close,
00491 .vredirect = xfer_vreopen,
00492 .window = unlimited_xfer_window,
00493 .alloc_iob = default_xfer_alloc_iob,
00494 .deliver_iob = http_socket_deliver_iob,
00495 .deliver_raw = xfer_deliver_as_iob,
00496 };
00497
00498
00499
00500
00501
00502
00503
00504 static void http_xfer_close ( struct xfer_interface *xfer, int rc ) {
00505 struct http_request *http =
00506 container_of ( xfer, struct http_request, xfer );
00507
00508 DBGC ( http, "HTTP %p interface closed: %s\n",
00509 http, strerror ( rc ) );
00510
00511 http_done ( http, rc );
00512 }
00513
00514
00515 static struct xfer_interface_operations http_xfer_operations = {
00516 .close = http_xfer_close,
00517 .vredirect = ignore_xfer_vredirect,
00518 .window = unlimited_xfer_window,
00519 .alloc_iob = default_xfer_alloc_iob,
00520 .deliver_iob = xfer_deliver_as_raw,
00521 .deliver_raw = ignore_xfer_deliver_raw,
00522 };
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533 int http_open_filter ( struct xfer_interface *xfer, struct uri *uri,
00534 unsigned int default_port,
00535 int ( * filter ) ( struct xfer_interface *xfer,
00536 struct xfer_interface **next ) ) {
00537 struct http_request *http;
00538 struct sockaddr_tcpip server;
00539 struct xfer_interface *socket;
00540 int rc;
00541
00542
00543 if ( ! uri->host )
00544 return -EINVAL;
00545
00546
00547 http = zalloc ( sizeof ( *http ) );
00548 if ( ! http )
00549 return -ENOMEM;
00550 http->refcnt.free = http_free;
00551 xfer_init ( &http->xfer, &http_xfer_operations, &http->refcnt );
00552 http->uri = uri_get ( uri );
00553 xfer_init ( &http->socket, &http_socket_operations, &http->refcnt );
00554 process_init ( &http->process, http_step, &http->refcnt );
00555
00556
00557 memset ( &server, 0, sizeof ( server ) );
00558 server.st_port = htons ( uri_port ( http->uri, default_port ) );
00559 socket = &http->socket;
00560 if ( filter ) {
00561 if ( ( rc = filter ( socket, &socket ) ) != 0 )
00562 goto err;
00563 }
00564 if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
00565 ( struct sockaddr * ) &server,
00566 uri->host, NULL ) ) != 0 )
00567 goto err;
00568
00569
00570 xfer_plug_plug ( &http->xfer, xfer );
00571 ref_put ( &http->refcnt );
00572 return 0;
00573
00574 err:
00575 DBGC ( http, "HTTP %p could not create request: %s\n",
00576 http, strerror ( rc ) );
00577 http_done ( http, rc );
00578 ref_put ( &http->refcnt );
00579 return rc;
00580 }
00581
00582
00583
00584
00585
00586
00587
00588
00589 static int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
00590 return http_open_filter ( xfer, uri, HTTP_PORT, NULL );
00591 }
00592
00593
00594 struct uri_opener http_uri_opener __uri_opener = {
00595 .scheme = "http",
00596 .open = http_open,
00597 };