You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

httpcore.c 23KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  1. /*
  2. * Copyright (C) 2007 Michael Brown <mbrown@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. FILE_LICENCE ( GPL2_OR_LATER );
  19. /**
  20. * @file
  21. *
  22. * Hyper Text Transfer Protocol (HTTP) core functionality
  23. *
  24. */
  25. #include <stdint.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <strings.h>
  30. #include <byteswap.h>
  31. #include <errno.h>
  32. #include <assert.h>
  33. #include <ipxe/uri.h>
  34. #include <ipxe/refcnt.h>
  35. #include <ipxe/iobuf.h>
  36. #include <ipxe/xfer.h>
  37. #include <ipxe/open.h>
  38. #include <ipxe/socket.h>
  39. #include <ipxe/tcpip.h>
  40. #include <ipxe/process.h>
  41. #include <ipxe/linebuf.h>
  42. #include <ipxe/base64.h>
  43. #include <ipxe/blockdev.h>
  44. #include <ipxe/acpi.h>
  45. #include <ipxe/http.h>
  46. /** Block size used for HTTP block device request */
  47. #define HTTP_BLKSIZE 512
  48. /** HTTP flags */
  49. enum http_flags {
  50. /** Request is waiting to be transmitted */
  51. HTTP_TX_PENDING = 0x0001,
  52. /** Fetch header only */
  53. HTTP_HEAD_ONLY = 0x0002,
  54. /** Keep connection alive */
  55. HTTP_KEEPALIVE = 0x0004,
  56. };
  57. /** HTTP receive state */
  58. enum http_rx_state {
  59. HTTP_RX_RESPONSE = 0,
  60. HTTP_RX_HEADER,
  61. HTTP_RX_CHUNK_LEN,
  62. HTTP_RX_DATA,
  63. HTTP_RX_TRAILER,
  64. HTTP_RX_IDLE,
  65. HTTP_RX_DEAD,
  66. };
  67. /**
  68. * An HTTP request
  69. *
  70. */
  71. struct http_request {
  72. /** Reference count */
  73. struct refcnt refcnt;
  74. /** Data transfer interface */
  75. struct interface xfer;
  76. /** Partial transfer interface */
  77. struct interface partial;
  78. /** URI being fetched */
  79. struct uri *uri;
  80. /** Transport layer interface */
  81. struct interface socket;
  82. /** Flags */
  83. unsigned int flags;
  84. /** Starting offset of partial transfer (if applicable) */
  85. size_t partial_start;
  86. /** Length of partial transfer (if applicable) */
  87. size_t partial_len;
  88. /** TX process */
  89. struct process process;
  90. /** RX state */
  91. enum http_rx_state rx_state;
  92. /** Received length */
  93. size_t rx_len;
  94. /** Length remaining (or 0 if unknown) */
  95. size_t remaining;
  96. /** HTTP is using Transfer-Encoding: chunked */
  97. int chunked;
  98. /** Current chunk length remaining (if applicable) */
  99. size_t chunk_remaining;
  100. /** Line buffer for received header lines */
  101. struct line_buffer linebuf;
  102. /** Receive data buffer (if applicable) */
  103. userptr_t rx_buffer;
  104. };
  105. /**
  106. * Free HTTP request
  107. *
  108. * @v refcnt Reference counter
  109. */
  110. static void http_free ( struct refcnt *refcnt ) {
  111. struct http_request *http =
  112. container_of ( refcnt, struct http_request, refcnt );
  113. uri_put ( http->uri );
  114. empty_line_buffer ( &http->linebuf );
  115. free ( http );
  116. };
  117. /**
  118. * Close HTTP request
  119. *
  120. * @v http HTTP request
  121. * @v rc Return status code
  122. */
  123. static void http_close ( struct http_request *http, int rc ) {
  124. /* Prevent further processing of any current packet */
  125. http->rx_state = HTTP_RX_DEAD;
  126. /* If we had a Content-Length, and the received content length
  127. * isn't correct, flag an error
  128. */
  129. if ( http->remaining != 0 ) {
  130. DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
  131. http, http->rx_len, ( http->rx_len + http->remaining ) );
  132. if ( rc == 0 )
  133. rc = -EIO;
  134. }
  135. /* Remove process */
  136. process_del ( &http->process );
  137. /* Close all data transfer interfaces */
  138. intf_shutdown ( &http->socket, rc );
  139. intf_shutdown ( &http->partial, rc );
  140. intf_shutdown ( &http->xfer, rc );
  141. }
  142. /**
  143. * Mark HTTP request as completed successfully
  144. *
  145. * @v http HTTP request
  146. */
  147. static void http_done ( struct http_request *http ) {
  148. /* If we had a Content-Length, and the received content length
  149. * isn't correct, force an error
  150. */
  151. if ( http->remaining != 0 ) {
  152. http_close ( http, -EIO );
  153. return;
  154. }
  155. /* Enter idle state */
  156. http->rx_state = HTTP_RX_IDLE;
  157. http->rx_len = 0;
  158. assert ( http->remaining == 0 );
  159. assert ( http->chunked == 0 );
  160. assert ( http->chunk_remaining == 0 );
  161. /* Close partial transfer interface */
  162. intf_restart ( &http->partial, 0 );
  163. /* Close everything unless we are keeping the connection alive */
  164. if ( ! ( http->flags & HTTP_KEEPALIVE ) )
  165. http_close ( http, 0 );
  166. }
  167. /**
  168. * Convert HTTP response code to return status code
  169. *
  170. * @v response HTTP response code
  171. * @ret rc Return status code
  172. */
  173. static int http_response_to_rc ( unsigned int response ) {
  174. switch ( response ) {
  175. case 200:
  176. case 206:
  177. case 301:
  178. case 302:
  179. case 303:
  180. return 0;
  181. case 404:
  182. return -ENOENT;
  183. case 403:
  184. return -EPERM;
  185. case 401:
  186. return -EACCES;
  187. default:
  188. return -EIO;
  189. }
  190. }
  191. /**
  192. * Handle HTTP response
  193. *
  194. * @v http HTTP request
  195. * @v response HTTP response
  196. * @ret rc Return status code
  197. */
  198. static int http_rx_response ( struct http_request *http, char *response ) {
  199. char *spc;
  200. unsigned int code;
  201. int rc;
  202. DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
  203. /* Check response starts with "HTTP/" */
  204. if ( strncmp ( response, "HTTP/", 5 ) != 0 )
  205. return -EIO;
  206. /* Locate and check response code */
  207. spc = strchr ( response, ' ' );
  208. if ( ! spc )
  209. return -EIO;
  210. code = strtoul ( spc, NULL, 10 );
  211. if ( ( rc = http_response_to_rc ( code ) ) != 0 )
  212. return rc;
  213. /* Move to received headers */
  214. http->rx_state = HTTP_RX_HEADER;
  215. return 0;
  216. }
  217. /**
  218. * Handle HTTP Location header
  219. *
  220. * @v http HTTP request
  221. * @v value HTTP header value
  222. * @ret rc Return status code
  223. */
  224. static int http_rx_location ( struct http_request *http, const char *value ) {
  225. int rc;
  226. /* Redirect to new location */
  227. DBGC ( http, "HTTP %p redirecting to %s\n", http, value );
  228. if ( ( rc = xfer_redirect ( &http->xfer, LOCATION_URI_STRING,
  229. value ) ) != 0 ) {
  230. DBGC ( http, "HTTP %p could not redirect: %s\n",
  231. http, strerror ( rc ) );
  232. return rc;
  233. }
  234. return 0;
  235. }
  236. /**
  237. * Handle HTTP Content-Length header
  238. *
  239. * @v http HTTP request
  240. * @v value HTTP header value
  241. * @ret rc Return status code
  242. */
  243. static int http_rx_content_length ( struct http_request *http,
  244. const char *value ) {
  245. struct block_device_capacity capacity;
  246. size_t content_len;
  247. char *endp;
  248. /* Parse content length */
  249. content_len = strtoul ( value, &endp, 10 );
  250. if ( *endp != '\0' ) {
  251. DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
  252. http, value );
  253. return -EIO;
  254. }
  255. /* If we already have an expected content length, and this
  256. * isn't it, then complain
  257. */
  258. if ( http->remaining && ( http->remaining != content_len ) ) {
  259. DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected "
  260. "%zd)\n", http, content_len, http->remaining );
  261. return -EIO;
  262. }
  263. if ( ! ( http->flags & HTTP_HEAD_ONLY ) )
  264. http->remaining = content_len;
  265. /* Use seek() to notify recipient of filesize */
  266. xfer_seek ( &http->xfer, http->remaining );
  267. xfer_seek ( &http->xfer, 0 );
  268. /* Report block device capacity if applicable */
  269. if ( http->flags & HTTP_HEAD_ONLY ) {
  270. capacity.blocks = ( content_len / HTTP_BLKSIZE );
  271. capacity.blksize = HTTP_BLKSIZE;
  272. capacity.max_count = -1U;
  273. block_capacity ( &http->partial, &capacity );
  274. }
  275. return 0;
  276. }
  277. /**
  278. * Handle HTTP Transfer-Encoding header
  279. *
  280. * @v http HTTP request
  281. * @v value HTTP header value
  282. * @ret rc Return status code
  283. */
  284. static int http_rx_transfer_encoding ( struct http_request *http,
  285. const char *value ) {
  286. if ( strcmp ( value, "chunked" ) == 0 ) {
  287. /* Mark connection as using chunked transfer encoding */
  288. http->chunked = 1;
  289. }
  290. return 0;
  291. }
  292. /** An HTTP header handler */
  293. struct http_header_handler {
  294. /** Name (e.g. "Content-Length") */
  295. const char *header;
  296. /** Handle received header
  297. *
  298. * @v http HTTP request
  299. * @v value HTTP header value
  300. * @ret rc Return status code
  301. *
  302. * If an error is returned, the download will be aborted.
  303. */
  304. int ( * rx ) ( struct http_request *http, const char *value );
  305. };
  306. /** List of HTTP header handlers */
  307. static struct http_header_handler http_header_handlers[] = {
  308. {
  309. .header = "Location",
  310. .rx = http_rx_location,
  311. },
  312. {
  313. .header = "Content-Length",
  314. .rx = http_rx_content_length,
  315. },
  316. {
  317. .header = "Transfer-Encoding",
  318. .rx = http_rx_transfer_encoding,
  319. },
  320. { NULL, NULL }
  321. };
  322. /**
  323. * Handle HTTP header
  324. *
  325. * @v http HTTP request
  326. * @v header HTTP header
  327. * @ret rc Return status code
  328. */
  329. static int http_rx_header ( struct http_request *http, char *header ) {
  330. struct http_header_handler *handler;
  331. char *separator;
  332. char *value;
  333. int rc;
  334. /* An empty header line marks the end of this phase */
  335. if ( ! header[0] ) {
  336. empty_line_buffer ( &http->linebuf );
  337. if ( ( http->rx_state == HTTP_RX_HEADER ) &&
  338. ( ! ( http->flags & HTTP_HEAD_ONLY ) ) ) {
  339. DBGC ( http, "HTTP %p start of data\n", http );
  340. http->rx_state = ( http->chunked ?
  341. HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
  342. return 0;
  343. } else {
  344. DBGC ( http, "HTTP %p end of trailer\n", http );
  345. http_done ( http );
  346. return 0;
  347. }
  348. }
  349. DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
  350. /* Split header at the ": " */
  351. separator = strstr ( header, ": " );
  352. if ( ! separator ) {
  353. DBGC ( http, "HTTP %p malformed header\n", http );
  354. return -EIO;
  355. }
  356. *separator = '\0';
  357. value = ( separator + 2 );
  358. /* Hand off to header handler, if one exists */
  359. for ( handler = http_header_handlers ; handler->header ; handler++ ) {
  360. if ( strcasecmp ( header, handler->header ) == 0 ) {
  361. if ( ( rc = handler->rx ( http, value ) ) != 0 )
  362. return rc;
  363. break;
  364. }
  365. }
  366. return 0;
  367. }
  368. /**
  369. * Handle HTTP chunk length
  370. *
  371. * @v http HTTP request
  372. * @v length HTTP chunk length
  373. * @ret rc Return status code
  374. */
  375. static int http_rx_chunk_len ( struct http_request *http, char *length ) {
  376. char *endp;
  377. /* Skip blank lines between chunks */
  378. if ( length[0] == '\0' )
  379. return 0;
  380. /* Parse chunk length */
  381. http->chunk_remaining = strtoul ( length, &endp, 16 );
  382. if ( *endp != '\0' ) {
  383. DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
  384. http, length );
  385. return -EIO;
  386. }
  387. /* Terminate chunked encoding if applicable */
  388. if ( http->chunk_remaining == 0 ) {
  389. DBGC ( http, "HTTP %p end of chunks\n", http );
  390. http->chunked = 0;
  391. http->rx_state = HTTP_RX_TRAILER;
  392. return 0;
  393. }
  394. /* Use seek() to notify recipient of new filesize */
  395. DBGC ( http, "HTTP %p start of chunk of length %zd\n",
  396. http, http->chunk_remaining );
  397. xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_remaining ) );
  398. xfer_seek ( &http->xfer, http->rx_len );
  399. /* Start receiving data */
  400. http->rx_state = HTTP_RX_DATA;
  401. return 0;
  402. }
  403. /** An HTTP line-based data handler */
  404. struct http_line_handler {
  405. /** Handle line
  406. *
  407. * @v http HTTP request
  408. * @v line Line to handle
  409. * @ret rc Return status code
  410. */
  411. int ( * rx ) ( struct http_request *http, char *line );
  412. };
  413. /** List of HTTP line-based data handlers */
  414. static struct http_line_handler http_line_handlers[] = {
  415. [HTTP_RX_RESPONSE] = { .rx = http_rx_response },
  416. [HTTP_RX_HEADER] = { .rx = http_rx_header },
  417. [HTTP_RX_CHUNK_LEN] = { .rx = http_rx_chunk_len },
  418. [HTTP_RX_TRAILER] = { .rx = http_rx_header },
  419. };
  420. /**
  421. * Handle new data arriving via HTTP connection
  422. *
  423. * @v http HTTP request
  424. * @v iobuf I/O buffer
  425. * @v meta Data transfer metadata
  426. * @ret rc Return status code
  427. */
  428. static int http_socket_deliver ( struct http_request *http,
  429. struct io_buffer *iobuf,
  430. struct xfer_metadata *meta __unused ) {
  431. struct http_line_handler *lh;
  432. char *line;
  433. size_t data_len;
  434. ssize_t line_len;
  435. int rc = 0;
  436. while ( iobuf && iob_len ( iobuf ) ) {
  437. switch ( http->rx_state ) {
  438. case HTTP_RX_IDLE:
  439. /* Receiving any data in this state is an error */
  440. DBGC ( http, "HTTP %p received %zd bytes while %s\n",
  441. http, iob_len ( iobuf ),
  442. ( ( http->rx_state == HTTP_RX_IDLE ) ?
  443. "idle" : "dead" ) );
  444. rc = -EPROTO;
  445. goto done;
  446. case HTTP_RX_DEAD:
  447. /* Do no further processing */
  448. goto done;
  449. case HTTP_RX_DATA:
  450. /* Pass received data to caller */
  451. data_len = iob_len ( iobuf );
  452. if ( http->chunk_remaining &&
  453. ( http->chunk_remaining < data_len ) ) {
  454. data_len = http->chunk_remaining;
  455. }
  456. if ( http->remaining &&
  457. ( http->remaining < data_len ) ) {
  458. data_len = http->remaining;
  459. }
  460. if ( http->rx_buffer != UNULL ) {
  461. /* Copy to partial transfer buffer */
  462. copy_to_user ( http->rx_buffer, http->rx_len,
  463. iobuf->data, data_len );
  464. iob_pull ( iobuf, data_len );
  465. } else if ( data_len < iob_len ( iobuf ) ) {
  466. /* Deliver partial buffer as raw data */
  467. rc = xfer_deliver_raw ( &http->xfer,
  468. iobuf->data, data_len );
  469. iob_pull ( iobuf, data_len );
  470. if ( rc != 0 )
  471. goto done;
  472. } else {
  473. /* Deliver whole I/O buffer */
  474. if ( ( rc = xfer_deliver_iob ( &http->xfer,
  475. iob_disown ( iobuf ) ) ) != 0 )
  476. goto done;
  477. }
  478. http->rx_len += data_len;
  479. if ( http->chunk_remaining ) {
  480. http->chunk_remaining -= data_len;
  481. if ( http->chunk_remaining == 0 )
  482. http->rx_state = HTTP_RX_CHUNK_LEN;
  483. }
  484. if ( http->remaining ) {
  485. http->remaining -= data_len;
  486. if ( ( http->remaining == 0 ) &&
  487. ( http->rx_state == HTTP_RX_DATA ) ) {
  488. http_done ( http );
  489. }
  490. }
  491. break;
  492. case HTTP_RX_RESPONSE:
  493. case HTTP_RX_HEADER:
  494. case HTTP_RX_CHUNK_LEN:
  495. case HTTP_RX_TRAILER:
  496. /* In the other phases, buffer and process a
  497. * line at a time
  498. */
  499. line_len = line_buffer ( &http->linebuf, iobuf->data,
  500. iob_len ( iobuf ) );
  501. if ( line_len < 0 ) {
  502. rc = line_len;
  503. DBGC ( http, "HTTP %p could not buffer line: "
  504. "%s\n", http, strerror ( rc ) );
  505. goto done;
  506. }
  507. iob_pull ( iobuf, line_len );
  508. line = buffered_line ( &http->linebuf );
  509. if ( line ) {
  510. lh = &http_line_handlers[http->rx_state];
  511. if ( ( rc = lh->rx ( http, line ) ) != 0 )
  512. goto done;
  513. }
  514. break;
  515. default:
  516. assert ( 0 );
  517. break;
  518. }
  519. }
  520. done:
  521. if ( rc )
  522. http_close ( http, rc );
  523. free_iob ( iobuf );
  524. return rc;
  525. }
  526. /**
  527. * Check HTTP socket flow control window
  528. *
  529. * @v http HTTP request
  530. * @ret len Length of window
  531. */
  532. static size_t http_socket_window ( struct http_request *http __unused ) {
  533. /* Window is always open. This is to prevent TCP from
  534. * stalling if our parent window is not currently open.
  535. */
  536. return ( ~( ( size_t ) 0 ) );
  537. }
  538. /**
  539. * HTTP process
  540. *
  541. * @v http HTTP request
  542. */
  543. static void http_step ( struct http_request *http ) {
  544. const char *host = http->uri->host;
  545. const char *user = http->uri->user;
  546. const char *password =
  547. ( http->uri->password ? http->uri->password : "" );
  548. size_t user_pw_len = ( user ? ( strlen ( user ) + 1 /* ":" */ +
  549. strlen ( password ) ) : 0 );
  550. size_t user_pw_base64_len = base64_encoded_len ( user_pw_len );
  551. uint8_t user_pw[ user_pw_len + 1 /* NUL */ ];
  552. char user_pw_base64[ user_pw_base64_len + 1 /* NUL */ ];
  553. int rc;
  554. int request_len = unparse_uri ( NULL, 0, http->uri,
  555. URI_PATH_BIT | URI_QUERY_BIT );
  556. char request[ request_len + 1 /* NUL */ ];
  557. char range[48]; /* Enough for two 64-bit integers in decimal */
  558. int partial;
  559. /* Do nothing if we have already transmitted the request */
  560. if ( ! ( http->flags & HTTP_TX_PENDING ) )
  561. return;
  562. /* Do nothing until socket is ready */
  563. if ( ! xfer_window ( &http->socket ) )
  564. return;
  565. /* Construct path?query request */
  566. unparse_uri ( request, sizeof ( request ), http->uri,
  567. URI_PATH_BIT | URI_QUERY_BIT );
  568. /* Construct authorisation, if applicable */
  569. if ( user ) {
  570. /* Make "user:password" string from decoded fields */
  571. snprintf ( ( ( char * ) user_pw ), sizeof ( user_pw ),
  572. "%s:%s", user, password );
  573. /* Base64-encode the "user:password" string */
  574. base64_encode ( user_pw, user_pw_len, user_pw_base64 );
  575. }
  576. /* Force a HEAD request if we have nowhere to send any received data */
  577. if ( ( xfer_window ( &http->xfer ) == 0 ) &&
  578. ( http->rx_buffer == UNULL ) ) {
  579. http->flags |= ( HTTP_HEAD_ONLY | HTTP_KEEPALIVE );
  580. }
  581. /* Determine type of request */
  582. partial = ( http->partial_len != 0 );
  583. snprintf ( range, sizeof ( range ), "%zd-%zd", http->partial_start,
  584. ( http->partial_start + http->partial_len - 1 ) );
  585. /* Mark request as transmitted */
  586. http->flags &= ~HTTP_TX_PENDING;
  587. /* Send GET request */
  588. if ( ( rc = xfer_printf ( &http->socket,
  589. "%s %s%s HTTP/1.1\r\n"
  590. "User-Agent: iPXE/" VERSION "\r\n"
  591. "Host: %s%s%s\r\n"
  592. "%s%s%s%s%s%s%s"
  593. "\r\n",
  594. ( ( http->flags & HTTP_HEAD_ONLY ) ?
  595. "HEAD" : "GET" ),
  596. ( http->uri->path ? "" : "/" ),
  597. request, host,
  598. ( http->uri->port ?
  599. ":" : "" ),
  600. ( http->uri->port ?
  601. http->uri->port : "" ),
  602. ( ( http->flags & HTTP_KEEPALIVE ) ?
  603. "Connection: Keep-Alive\r\n" : "" ),
  604. ( partial ? "Range: bytes=" : "" ),
  605. ( partial ? range : "" ),
  606. ( partial ? "\r\n" : "" ),
  607. ( user ?
  608. "Authorization: Basic " : "" ),
  609. ( user ? user_pw_base64 : "" ),
  610. ( user ? "\r\n" : "" ) ) ) != 0 ) {
  611. http_close ( http, rc );
  612. }
  613. }
  614. /**
  615. * Check HTTP data transfer flow control window
  616. *
  617. * @v http HTTP request
  618. * @ret len Length of window
  619. */
  620. static size_t http_xfer_window ( struct http_request *http ) {
  621. /* New block commands may be issued only when we are idle */
  622. return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 );
  623. }
  624. /**
  625. * Initiate HTTP partial read
  626. *
  627. * @v http HTTP request
  628. * @v partial Partial transfer interface
  629. * @v offset Starting offset
  630. * @v buffer Data buffer
  631. * @v len Length
  632. * @ret rc Return status code
  633. */
  634. static int http_partial_read ( struct http_request *http,
  635. struct interface *partial,
  636. size_t offset, userptr_t buffer, size_t len ) {
  637. /* Sanity check */
  638. if ( http_xfer_window ( http ) == 0 )
  639. return -EBUSY;
  640. /* Initialise partial transfer parameters */
  641. http->rx_buffer = buffer;
  642. http->partial_start = offset;
  643. http->partial_len = len;
  644. http->remaining = len;
  645. /* Schedule request */
  646. http->rx_state = HTTP_RX_RESPONSE;
  647. http->flags = ( HTTP_TX_PENDING | HTTP_KEEPALIVE );
  648. if ( ! len )
  649. http->flags |= HTTP_HEAD_ONLY;
  650. process_add ( &http->process );
  651. /* Attach to parent interface and return */
  652. intf_plug_plug ( &http->partial, partial );
  653. return 0;
  654. }
  655. /**
  656. * Issue HTTP block device read
  657. *
  658. * @v http HTTP request
  659. * @v block Block data interface
  660. * @v lba Starting logical block address
  661. * @v count Number of blocks to transfer
  662. * @v buffer Data buffer
  663. * @v len Length of data buffer
  664. * @ret rc Return status code
  665. */
  666. static int http_block_read ( struct http_request *http,
  667. struct interface *block,
  668. uint64_t lba, unsigned int count,
  669. userptr_t buffer, size_t len __unused ) {
  670. return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ),
  671. buffer, ( count * HTTP_BLKSIZE ) );
  672. }
  673. /**
  674. * Read HTTP block device capacity
  675. *
  676. * @v http HTTP request
  677. * @v block Block data interface
  678. * @ret rc Return status code
  679. */
  680. static int http_block_read_capacity ( struct http_request *http,
  681. struct interface *block ) {
  682. return http_partial_read ( http, block, 0, 0, 0 );
  683. }
  684. /**
  685. * Describe HTTP device in an ACPI table
  686. *
  687. * @v http HTTP request
  688. * @v acpi ACPI table
  689. * @v len Length of ACPI table
  690. * @ret rc Return status code
  691. */
  692. static int http_acpi_describe ( struct http_request *http,
  693. struct acpi_description_header *acpi,
  694. size_t len ) {
  695. DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
  696. http );
  697. ( void ) acpi;
  698. ( void ) len;
  699. return 0;
  700. }
  701. /** HTTP socket interface operations */
  702. static struct interface_operation http_socket_operations[] = {
  703. INTF_OP ( xfer_window, struct http_request *, http_socket_window ),
  704. INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
  705. INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
  706. INTF_OP ( intf_close, struct http_request *, http_close ),
  707. };
  708. /** HTTP socket interface descriptor */
  709. static struct interface_descriptor http_socket_desc =
  710. INTF_DESC_PASSTHRU ( struct http_request, socket,
  711. http_socket_operations, xfer );
  712. /** HTTP partial transfer interface operations */
  713. static struct interface_operation http_partial_operations[] = {
  714. INTF_OP ( intf_close, struct http_request *, http_close ),
  715. };
  716. /** HTTP partial transfer interface descriptor */
  717. static struct interface_descriptor http_partial_desc =
  718. INTF_DESC ( struct http_request, partial, http_partial_operations );
  719. /** HTTP data transfer interface operations */
  720. static struct interface_operation http_xfer_operations[] = {
  721. INTF_OP ( xfer_window, struct http_request *, http_xfer_window ),
  722. INTF_OP ( block_read, struct http_request *, http_block_read ),
  723. INTF_OP ( block_read_capacity, struct http_request *,
  724. http_block_read_capacity ),
  725. INTF_OP ( intf_close, struct http_request *, http_close ),
  726. INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ),
  727. };
  728. /** HTTP data transfer interface descriptor */
  729. static struct interface_descriptor http_xfer_desc =
  730. INTF_DESC_PASSTHRU ( struct http_request, xfer,
  731. http_xfer_operations, socket );
  732. /** HTTP process descriptor */
  733. static struct process_descriptor http_process_desc =
  734. PROC_DESC_ONCE ( struct http_request, process, http_step );
  735. /**
  736. * Initiate an HTTP connection, with optional filter
  737. *
  738. * @v xfer Data transfer interface
  739. * @v uri Uniform Resource Identifier
  740. * @v default_port Default port number
  741. * @v filter Filter to apply to socket, or NULL
  742. * @ret rc Return status code
  743. */
  744. int http_open_filter ( struct interface *xfer, struct uri *uri,
  745. unsigned int default_port,
  746. int ( * filter ) ( struct interface *xfer,
  747. const char *name,
  748. struct interface **next ) ) {
  749. struct http_request *http;
  750. struct sockaddr_tcpip server;
  751. struct interface *socket;
  752. int rc;
  753. /* Sanity checks */
  754. if ( ! uri->host )
  755. return -EINVAL;
  756. /* Allocate and populate HTTP structure */
  757. http = zalloc ( sizeof ( *http ) );
  758. if ( ! http )
  759. return -ENOMEM;
  760. ref_init ( &http->refcnt, http_free );
  761. intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
  762. intf_init ( &http->partial, &http_partial_desc, &http->refcnt );
  763. http->uri = uri_get ( uri );
  764. intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
  765. process_init ( &http->process, &http_process_desc, &http->refcnt );
  766. http->flags = HTTP_TX_PENDING;
  767. /* Open socket */
  768. memset ( &server, 0, sizeof ( server ) );
  769. server.st_port = htons ( uri_port ( http->uri, default_port ) );
  770. socket = &http->socket;
  771. if ( filter ) {
  772. if ( ( rc = filter ( socket, uri->host, &socket ) ) != 0 )
  773. goto err;
  774. }
  775. if ( ( rc = xfer_open_named_socket ( socket, SOCK_STREAM,
  776. ( struct sockaddr * ) &server,
  777. uri->host, NULL ) ) != 0 )
  778. goto err;
  779. /* Attach to parent interface, mortalise self, and return */
  780. intf_plug_plug ( &http->xfer, xfer );
  781. ref_put ( &http->refcnt );
  782. return 0;
  783. err:
  784. DBGC ( http, "HTTP %p could not create request: %s\n",
  785. http, strerror ( rc ) );
  786. http_close ( http, rc );
  787. ref_put ( &http->refcnt );
  788. return rc;
  789. }