2 * Copyright (C) 2015 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL
);
29 * Hyper Text Transfer Protocol (HTTP) core functionality
43 #include <ipxe/refcnt.h>
44 #include <ipxe/iobuf.h>
45 #include <ipxe/xfer.h>
46 #include <ipxe/open.h>
47 #include <ipxe/process.h>
48 #include <ipxe/retry.h>
49 #include <ipxe/timer.h>
50 #include <ipxe/linebuf.h>
51 #include <ipxe/xferbuf.h>
52 #include <ipxe/blockdev.h>
53 #include <ipxe/acpi.h>
54 #include <ipxe/version.h>
55 #include <ipxe/params.h>
56 #include <ipxe/profile.h>
57 #include <ipxe/vsprintf.h>
58 #include <ipxe/http.h>
60 /* Disambiguate the various error causes */
61 #define EACCES_401 __einfo_error ( EINFO_EACCES_401 )
62 #define EINFO_EACCES_401 \
63 __einfo_uniqify ( EINFO_EACCES, 0x01, "HTTP 401 Unauthorized" )
64 #define EINVAL_STATUS __einfo_error ( EINFO_EINVAL_STATUS )
65 #define EINFO_EINVAL_STATUS \
66 __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid status line" )
67 #define EINVAL_HEADER __einfo_error ( EINFO_EINVAL_HEADER )
68 #define EINFO_EINVAL_HEADER \
69 __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid header" )
70 #define EINVAL_CONTENT_LENGTH __einfo_error ( EINFO_EINVAL_CONTENT_LENGTH )
71 #define EINFO_EINVAL_CONTENT_LENGTH \
72 __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid content length" )
73 #define EINVAL_CHUNK_LENGTH __einfo_error ( EINFO_EINVAL_CHUNK_LENGTH )
74 #define EINFO_EINVAL_CHUNK_LENGTH \
75 __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid chunk length" )
76 #define EIO_OTHER __einfo_error ( EINFO_EIO_OTHER )
77 #define EINFO_EIO_OTHER \
78 __einfo_uniqify ( EINFO_EIO, 0x01, "Unrecognised HTTP response code" )
79 #define EIO_CONTENT_LENGTH __einfo_error ( EINFO_EIO_CONTENT_LENGTH )
80 #define EINFO_EIO_CONTENT_LENGTH \
81 __einfo_uniqify ( EINFO_EIO, 0x02, "Content length mismatch" )
82 #define EIO_4XX __einfo_error ( EINFO_EIO_4XX )
83 #define EINFO_EIO_4XX \
84 __einfo_uniqify ( EINFO_EIO, 0x04, "HTTP 4xx Client Error" )
85 #define EIO_5XX __einfo_error ( EINFO_EIO_5XX )
86 #define EINFO_EIO_5XX \
87 __einfo_uniqify ( EINFO_EIO, 0x05, "HTTP 5xx Server Error" )
88 #define ENOENT_404 __einfo_error ( EINFO_ENOENT_404 )
89 #define EINFO_ENOENT_404 \
90 __einfo_uniqify ( EINFO_ENOENT, 0x01, "HTTP 404 Not Found" )
91 #define ENOTSUP_CONNECTION __einfo_error ( EINFO_ENOTSUP_CONNECTION )
92 #define EINFO_ENOTSUP_CONNECTION \
93 __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported connection header" )
94 #define ENOTSUP_TRANSFER __einfo_error ( EINFO_ENOTSUP_TRANSFER )
95 #define EINFO_ENOTSUP_TRANSFER \
96 __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported transfer encoding" )
97 #define EPERM_403 __einfo_error ( EINFO_EPERM_403 )
98 #define EINFO_EPERM_403 \
99 __einfo_uniqify ( EINFO_EPERM, 0x01, "HTTP 403 Forbidden" )
100 #define EPROTO_UNSOLICITED __einfo_error ( EINFO_EPROTO_UNSOLICITED )
101 #define EINFO_EPROTO_UNSOLICITED \
102 __einfo_uniqify ( EINFO_EPROTO, 0x01, "Unsolicited data" )
104 /** Retry delay used when we cannot understand the Retry-After header */
105 #define HTTP_RETRY_SECONDS 5
107 /** Receive profiler */
108 static struct profiler http_rx_profiler __profiler
= { .name
= "http.rx" };
110 /** Data transfer profiler */
111 static struct profiler http_xfer_profiler __profiler
= { .name
= "http.xfer" };
113 static struct http_state http_request
;
114 static struct http_state http_headers
;
115 static struct http_state http_trailers
;
116 static struct http_transfer_encoding http_transfer_identity
;
118 /******************************************************************************
122 ******************************************************************************
125 /** HTTP HEAD method */
126 struct http_method http_head
= {
130 /** HTTP GET method */
131 struct http_method http_get
= {
135 /** HTTP POST method */
136 struct http_method http_post
= {
140 /******************************************************************************
144 ******************************************************************************
148 * Handle received HTTP line-buffered data
150 * @v http HTTP transaction
151 * @v iobuf I/O buffer
152 * @v linebuf Line buffer
153 * @ret rc Return status code
155 static int http_rx_linebuf ( struct http_transaction
*http
,
156 struct io_buffer
*iobuf
,
157 struct line_buffer
*linebuf
) {
161 /* Buffer received line */
162 consumed
= line_buffer ( linebuf
, iobuf
->data
, iob_len ( iobuf
) );
163 if ( consumed
< 0 ) {
165 DBGC ( http
, "HTTP %p could not buffer line: %s\n",
166 http
, strerror ( rc
) );
171 iob_pull ( iobuf
, consumed
);
177 * Get HTTP response token
179 * @v line Line position
180 * @v value Token value to fill in (if any)
181 * @ret token Token, or NULL
183 char * http_token ( char **line
, char **value
) {
188 /* Avoid returning uninitialised data */
192 /* Skip any initial whitespace or commas */
193 while ( ( isspace ( **line
) ) || ( **line
== ',' ) )
196 /* Check for end of line and record token position */
201 /* Scan for end of token */
202 while ( ( c
= **line
) ) {
204 /* Terminate if we hit an unquoted whitespace or comma */
205 if ( ( isspace ( c
) || ( c
== ',' ) ) && ! quote
)
208 /* Terminate if we hit a closing quote */
212 /* Check for value separator */
213 if ( value
&& ( ! *value
) && ( c
== '=' ) ) {
215 /* Terminate key portion of token */
218 /* Check for quote character */
220 if ( ( c
== '"' ) || ( c
== '\'' ) ) {
225 /* Record value portion of token */
230 /* Move to next character */
235 /* Terminate token, if applicable */
242 /******************************************************************************
246 ******************************************************************************
250 * Free HTTP transaction
252 * @v refcnt Reference count
254 static void http_free ( struct refcnt
*refcnt
) {
255 struct http_transaction
*http
=
256 container_of ( refcnt
, struct http_transaction
, refcnt
);
258 empty_line_buffer ( &http
->response
.headers
);
259 empty_line_buffer ( &http
->linebuf
);
260 uri_put ( http
->uri
);
265 * Close HTTP transaction
267 * @v http HTTP transaction
268 * @v rc Reason for close
270 static void http_close ( struct http_transaction
*http
, int rc
) {
273 process_del ( &http
->process
);
276 stop_timer ( &http
->timer
);
278 /* Close all interfaces */
279 intfs_shutdown ( rc
, &http
->conn
, &http
->transfer
, &http
->content
,
284 * Close HTTP transaction with error (even if none specified)
286 * @v http HTTP transaction
287 * @v rc Reason for close
289 static void http_close_error ( struct http_transaction
*http
, int rc
) {
291 /* Treat any close as an error */
292 http_close ( http
, ( rc ? rc
: -EPIPE
) );
296 * Reopen stale HTTP connection
298 * @v http HTTP transaction
300 static void http_reopen ( struct http_transaction
*http
) {
303 /* Close existing connection */
304 intf_restart ( &http
->conn
, -ECANCELED
);
306 /* Reopen connection */
307 if ( ( rc
= http_connect ( &http
->conn
, http
->uri
) ) != 0 ) {
308 DBGC ( http
, "HTTP %p could not reconnect: %s\n",
309 http
, strerror ( rc
) );
314 http
->state
= &http_request
;
316 /* Reschedule transmission process */
317 process_add ( &http
->process
);
322 http_close ( http
, rc
);
326 * Handle retry timer expiry
328 * @v timer Retry timer
329 * @v over Failure indicator
331 static void http_expired ( struct retry_timer
*timer
, int over __unused
) {
332 struct http_transaction
*http
=
333 container_of ( timer
, struct http_transaction
, timer
);
335 /* Reopen connection */
336 http_reopen ( http
);
340 * HTTP transmit process
342 * @v http HTTP transaction
344 static void http_step ( struct http_transaction
*http
) {
347 /* Do nothing if we have nothing to transmit */
348 if ( ! http
->state
->tx
)
351 /* Do nothing until connection is ready */
352 if ( ! xfer_window ( &http
->conn
) )
355 /* Do nothing until data transfer interface is ready */
356 if ( ! xfer_window ( &http
->xfer
) )
360 if ( ( rc
= http
->state
->tx ( http
) ) != 0 )
366 http_close ( http
, rc
);
370 * Handle received HTTP data
372 * @v http HTTP transaction
373 * @v iobuf I/O buffer
374 * @v meta Transfer metadata
375 * @ret rc Return status code
377 * This function takes ownership of the I/O buffer.
379 static int http_conn_deliver ( struct http_transaction
*http
,
380 struct io_buffer
*iobuf
,
381 struct xfer_metadata
*meta __unused
) {
384 /* Handle received data */
385 profile_start ( &http_rx_profiler
);
386 while ( iobuf
&& iob_len ( iobuf
) ) {
389 if ( ( ! http
->state
) || ( ! http
->state
->rx
) ) {
390 DBGC ( http
, "HTTP %p unexpected data\n", http
);
391 rc
= -EPROTO_UNSOLICITED
;
395 /* Receive (some) data */
396 if ( ( rc
= http
->state
->rx ( http
, &iobuf
) ) != 0 )
400 /* Free I/O buffer, if applicable */
403 profile_stop ( &http_rx_profiler
);
408 http_close ( http
, rc
);
413 * Handle server connection close
415 * @v http HTTP transaction
416 * @v rc Reason for close
418 static void http_conn_close ( struct http_transaction
*http
, int rc
) {
421 assert ( http
->state
!= NULL
);
422 assert ( http
->state
->close
!= NULL
);
424 /* Restart server connection interface */
425 intf_restart ( &http
->conn
, rc
);
427 /* Hand off to state-specific method */
428 http
->state
->close ( http
, rc
);
432 * Handle received content-decoded data
434 * @v http HTTP transaction
435 * @v iobuf I/O buffer
436 * @v meta Data transfer metadata
438 static int http_content_deliver ( struct http_transaction
*http
,
439 struct io_buffer
*iobuf
,
440 struct xfer_metadata
*meta
) {
443 /* Ignore content if this is anything other than a successful
446 if ( http
->response
.rc
!= 0 ) {
451 /* Deliver to data transfer interface */
452 profile_start ( &http_xfer_profiler
);
453 if ( ( rc
= xfer_deliver ( &http
->xfer
, iob_disown ( iobuf
),
456 profile_stop ( &http_xfer_profiler
);
462 * Get underlying data transfer buffer
464 * @v http HTTP transaction
465 * @ret xferbuf Data transfer buffer, or NULL on error
467 static struct xfer_buffer
*
468 http_content_buffer ( struct http_transaction
*http
) {
470 /* Deny access to the data transfer buffer if this is anything
471 * other than a successful transfer.
473 if ( http
->response
.rc
!= 0 )
476 /* Hand off to data transfer interface */
477 return xfer_buffer ( &http
->xfer
);
481 * Read from block device (when HTTP block device support is not present)
483 * @v http HTTP transaction
484 * @v data Data interface
485 * @v lba Starting logical block address
486 * @v count Number of logical blocks
487 * @v buffer Data buffer
488 * @v len Length of data buffer
489 * @ret rc Return status code
491 __weak
int http_block_read ( struct http_transaction
*http __unused
,
492 struct interface
*data __unused
,
493 uint64_t lba __unused
, unsigned int count __unused
,
494 userptr_t buffer __unused
, size_t len __unused
) {
500 * Read block device capacity (when HTTP block device support is not present)
502 * @v control Control interface
503 * @v data Data interface
504 * @ret rc Return status code
506 __weak
int http_block_read_capacity ( struct http_transaction
*http __unused
,
507 struct interface
*data __unused
) {
513 * Describe device in ACPI table (when HTTP block device support is not present)
515 * @v http HTTP transaction
517 * @v len Length of ACPI table
518 * @ret rc Return status code
520 __weak
int http_acpi_describe ( struct http_transaction
*http __unused
,
521 struct acpi_description_header
*acpi __unused
,
522 size_t len __unused
) {
527 /** HTTP data transfer interface operations */
528 static struct interface_operation http_xfer_operations
[] = {
529 INTF_OP ( block_read
, struct http_transaction
*, http_block_read
),
530 INTF_OP ( block_read_capacity
, struct http_transaction
*,
531 http_block_read_capacity
),
532 INTF_OP ( acpi_describe
, struct http_transaction
*,
533 http_acpi_describe
),
534 INTF_OP ( xfer_window_changed
, struct http_transaction
*, http_step
),
535 INTF_OP ( intf_close
, struct http_transaction
*, http_close
),
538 /** HTTP data transfer interface descriptor */
539 static struct interface_descriptor http_xfer_desc
=
540 INTF_DESC_PASSTHRU ( struct http_transaction
, xfer
,
541 http_xfer_operations
, content
);
543 /** HTTP content-decoded interface operations */
544 static struct interface_operation http_content_operations
[] = {
545 INTF_OP ( xfer_deliver
, struct http_transaction
*,
546 http_content_deliver
),
547 INTF_OP ( xfer_buffer
, struct http_transaction
*, http_content_buffer
),
548 INTF_OP ( intf_close
, struct http_transaction
*, http_close
),
551 /** HTTP content-decoded interface descriptor */
552 static struct interface_descriptor http_content_desc
=
553 INTF_DESC_PASSTHRU ( struct http_transaction
, content
,
554 http_content_operations
, xfer
);
556 /** HTTP transfer-decoded interface operations */
557 static struct interface_operation http_transfer_operations
[] = {
558 INTF_OP ( intf_close
, struct http_transaction
*, http_close
),
561 /** HTTP transfer-decoded interface descriptor */
562 static struct interface_descriptor http_transfer_desc
=
563 INTF_DESC_PASSTHRU ( struct http_transaction
, transfer
,
564 http_transfer_operations
, conn
);
566 /** HTTP server connection interface operations */
567 static struct interface_operation http_conn_operations
[] = {
568 INTF_OP ( xfer_deliver
, struct http_transaction
*, http_conn_deliver
),
569 INTF_OP ( xfer_window_changed
, struct http_transaction
*, http_step
),
570 INTF_OP ( pool_reopen
, struct http_transaction
*, http_reopen
),
571 INTF_OP ( intf_close
, struct http_transaction
*, http_conn_close
),
574 /** HTTP server connection interface descriptor */
575 static struct interface_descriptor http_conn_desc
=
576 INTF_DESC_PASSTHRU ( struct http_transaction
, conn
,
577 http_conn_operations
, transfer
);
579 /** HTTP process descriptor */
580 static struct process_descriptor http_process_desc
=
581 PROC_DESC_ONCE ( struct http_transaction
, process
, http_step
);
584 * Open HTTP transaction
586 * @v xfer Data transfer interface
587 * @v method Request method
589 * @v range Content range (if any)
590 * @v content Request content (if any)
591 * @ret rc Return status code
593 int http_open ( struct interface
*xfer
, struct http_method
*method
,
594 struct uri
*uri
, struct http_request_range
*range
,
595 struct http_request_content
*content
) {
596 struct http_transaction
*http
;
597 struct uri request_uri
;
598 struct uri request_host
;
599 size_t request_uri_len
;
600 size_t request_host_len
;
602 char *request_uri_string
;
603 char *request_host_string
;
607 /* Calculate request URI length */
608 memset ( &request_uri
, 0, sizeof ( request_uri
) );
609 request_uri
.path
= ( uri
->path ? uri
->path
: "/" );
610 request_uri
.query
= uri
->query
;
612 ( format_uri ( &request_uri
, NULL
, 0 ) + 1 /* NUL */);
614 /* Calculate host name length */
615 memset ( &request_host
, 0, sizeof ( request_host
) );
616 request_host
.host
= uri
->host
;
617 request_host
.port
= uri
->port
;
619 ( format_uri ( &request_host
, NULL
, 0 ) + 1 /* NUL */ );
621 /* Calculate request content length */
622 content_len
= ( content ? content
->len
: 0 );
624 /* Allocate and initialise structure */
625 http
= zalloc ( sizeof ( *http
) + request_uri_len
+ request_host_len
+
631 request_uri_string
= ( ( ( void * ) http
) + sizeof ( *http
) );
632 request_host_string
= ( request_uri_string
+ request_uri_len
);
633 content_data
= ( request_host_string
+ request_host_len
);
634 format_uri ( &request_uri
, request_uri_string
, request_uri_len
);
635 format_uri ( &request_host
, request_host_string
, request_host_len
);
636 ref_init ( &http
->refcnt
, http_free
);
637 intf_init ( &http
->xfer
, &http_xfer_desc
, &http
->refcnt
);
638 intf_init ( &http
->content
, &http_content_desc
, &http
->refcnt
);
639 intf_init ( &http
->transfer
, &http_transfer_desc
, &http
->refcnt
);
640 intf_init ( &http
->conn
, &http_conn_desc
, &http
->refcnt
);
641 intf_plug_plug ( &http
->transfer
, &http
->content
);
642 process_init ( &http
->process
, &http_process_desc
, &http
->refcnt
);
643 timer_init ( &http
->timer
, http_expired
, &http
->refcnt
);
644 http
->uri
= uri_get ( uri
);
645 http
->request
.method
= method
;
646 http
->request
.uri
= request_uri_string
;
647 http
->request
.host
= request_host_string
;
649 memcpy ( &http
->request
.range
, range
,
650 sizeof ( http
->request
.range
) );
653 http
->request
.content
.type
= content
->type
;
654 http
->request
.content
.data
= content_data
;
655 http
->request
.content
.len
= content_len
;
656 memcpy ( content_data
, content
->data
, content_len
);
658 http
->state
= &http_request
;
659 DBGC2 ( http
, "HTTP %p %s://%s%s\n", http
, http
->uri
->scheme
,
660 http
->request
.host
, http
->request
.uri
);
662 /* Open connection */
663 if ( ( rc
= http_connect ( &http
->conn
, uri
) ) != 0 ) {
664 DBGC ( http
, "HTTP %p could not connect: %s\n",
665 http
, strerror ( rc
) );
669 /* Attach to parent interface, mortalise self, and return */
670 intf_plug_plug ( &http
->xfer
, xfer
);
671 ref_put ( &http
->refcnt
);
675 http_close ( http
, rc
);
676 ref_put ( &http
->refcnt
);
682 * Redirect HTTP transaction
684 * @v http HTTP transaction
685 * @v location New location
686 * @ret rc Return status code
688 static int http_redirect ( struct http_transaction
*http
,
689 const char *location
) {
690 struct uri
*location_uri
;
691 struct uri
*resolved_uri
;
694 DBGC2 ( http
, "HTTP %p redirecting to \"%s\"\n", http
, location
);
696 /* Parse location URI */
697 location_uri
= parse_uri ( location
);
698 if ( ! location_uri
) {
703 /* Resolve as relative to original URI */
704 resolved_uri
= resolve_uri ( http
->uri
, location_uri
);
705 if ( ! resolved_uri
) {
707 goto err_resolve_uri
;
710 /* Redirect to new URI */
711 if ( ( rc
= xfer_redirect ( &http
->xfer
, LOCATION_URI
,
712 resolved_uri
) ) != 0 ) {
713 DBGC ( http
, "HTTP %p could not redirect: %s\n",
714 http
, strerror ( rc
) );
719 uri_put ( resolved_uri
);
721 uri_put ( location_uri
);
727 * Handle successful transfer completion
729 * @v http HTTP transaction
730 * @ret rc Return status code
732 static int http_transfer_complete ( struct http_transaction
*http
) {
733 struct http_authentication
*auth
;
734 const char *location
;
737 /* Keep connection alive if applicable */
738 if ( http
->response
.flags
& HTTP_RESPONSE_KEEPALIVE
)
739 pool_recycle ( &http
->conn
);
741 /* Restart server connection interface */
742 intf_restart ( &http
->conn
, 0 );
744 /* No more data is expected */
747 /* If transaction is successful, then close the
748 * transfer-decoded interface. The content encoding may
749 * choose whether or not to immediately terminate the
752 if ( http
->response
.rc
== 0 ) {
753 intf_shutdown ( &http
->transfer
, 0 );
757 /* Perform redirection, if applicable */
758 if ( ( location
= http
->response
.location
) ) {
759 if ( ( rc
= http_redirect ( http
, location
) ) != 0 )
761 http_close ( http
, 0 );
765 /* Fail unless a retry is permitted */
766 if ( ! ( http
->response
.flags
& HTTP_RESPONSE_RETRY
) )
767 return http
->response
.rc
;
769 /* Perform authentication, if applicable */
770 if ( ( auth
= http
->response
.auth
.auth
) ) {
771 http
->request
.auth
.auth
= auth
;
772 DBGC2 ( http
, "HTTP %p performing %s authentication\n",
774 if ( ( rc
= auth
->authenticate ( http
) ) != 0 ) {
775 DBGC ( http
, "HTTP %p could not authenticate: %s\n",
776 http
, strerror ( rc
) );
781 /* Restart content decoding interfaces */
782 intfs_restart ( http
->response
.rc
, &http
->content
, &http
->transfer
,
784 intf_plug_plug ( &http
->transfer
, &http
->content
);
786 assert ( http
->remaining
== 0 );
788 /* Start timer to initiate retry */
789 DBGC2 ( http
, "HTTP %p retrying after %d seconds\n",
790 http
, http
->response
.retry_after
);
791 start_timer_fixed ( &http
->timer
,
792 ( http
->response
.retry_after
* TICKS_PER_SEC
) );
796 /******************************************************************************
800 ******************************************************************************
804 * Construct HTTP request headers
806 * @v http HTTP transaction
808 * @v len Length of buffer
809 * @ret len Length, or negative error
811 static int http_format_headers ( struct http_transaction
*http
, char *buf
,
813 struct http_request_header
*header
;
820 /* Construct request line */
821 used
= ssnprintf ( buf
, len
, "%s %s HTTP/1.1",
822 http
->request
.method
->name
, http
->request
.uri
);
824 DBGC2 ( http
, "HTTP %p TX %s\n", http
, buf
);
825 used
+= ssnprintf ( ( buf
+ used
), ( len
- used
), "\r\n" );
827 /* Construct all headers */
828 for_each_table_entry ( header
, HTTP_REQUEST_HEADERS
) {
830 /* Determine header value length */
831 value_len
= header
->format ( http
, NULL
, 0 );
832 if ( value_len
< 0 ) {
837 /* Skip zero-length headers */
841 /* Construct header */
842 line
= ( buf
+ used
);
843 used
+= ssnprintf ( ( buf
+ used
), ( len
- used
), "%s: ",
845 remaining
= ( ( used
< len
) ?
( len
- used
) : 0 );
846 used
+= header
->format ( http
, ( buf
+ used
), remaining
);
848 DBGC2 ( http
, "HTTP %p TX %s\n", http
, line
);
849 used
+= ssnprintf ( ( buf
+ used
), ( len
- used
), "\r\n" );
852 /* Construct terminating newline */
853 used
+= ssnprintf ( ( buf
+ used
), ( len
- used
), "\r\n" );
859 * Construct HTTP "Host" header
861 * @v http HTTP transaction
863 * @v len Length of buffer
864 * @ret len Length of header value, or negative error
866 static int http_format_host ( struct http_transaction
*http
, char *buf
,
869 /* Construct host URI */
870 return snprintf ( buf
, len
, "%s", http
->request
.host
);
873 /** HTTP "Host" header "*/
874 struct http_request_header http_request_host __http_request_header
= {
876 .format
= http_format_host
,
880 * Construct HTTP "User-Agent" header
882 * @v http HTTP transaction
884 * @v len Length of buffer
885 * @ret len Length of header value, or negative error
887 static int http_format_user_agent ( struct http_transaction
*http __unused
,
888 char *buf
, size_t len
) {
890 /* Construct user agent */
891 return snprintf ( buf
, len
, "iPXE/%s", product_version
);
894 /** HTTP "User-Agent" header */
895 struct http_request_header http_request_user_agent __http_request_header
= {
896 .name
= "User-Agent",
897 .format
= http_format_user_agent
,
901 * Construct HTTP "Connection" header
903 * @v http HTTP transaction
905 * @v len Length of buffer
906 * @ret len Length of header value, or negative error
908 static int http_format_connection ( struct http_transaction
*http __unused
,
909 char *buf
, size_t len
) {
911 /* Always request keep-alive */
912 return snprintf ( buf
, len
, "keep-alive" );
915 /** HTTP "Connection" header */
916 struct http_request_header http_request_connection __http_request_header
= {
917 .name
= "Connection",
918 .format
= http_format_connection
,
922 * Construct HTTP "Range" header
924 * @v http HTTP transaction
926 * @v len Length of buffer
927 * @ret len Length of header value, or negative error
929 static int http_format_range ( struct http_transaction
*http
,
930 char *buf
, size_t len
) {
932 /* Construct range, if applicable */
933 if ( http
->request
.range
.len
) {
934 return snprintf ( buf
, len
, "bytes=%zd-%zd",
935 http
->request
.range
.start
,
936 ( http
->request
.range
.start
+
937 http
->request
.range
.len
- 1 ) );
943 /** HTTP "Range" header */
944 struct http_request_header http_request_range __http_request_header
= {
946 .format
= http_format_range
,
950 * Construct HTTP "Content-Type" header
952 * @v http HTTP transaction
954 * @v len Length of buffer
955 * @ret len Length of header value, or negative error
957 static int http_format_content_type ( struct http_transaction
*http
,
958 char *buf
, size_t len
) {
960 /* Construct content type, if applicable */
961 if ( http
->request
.content
.type
) {
962 return snprintf ( buf
, len
, "%s", http
->request
.content
.type
);
968 /** HTTP "Content-Type" header */
969 struct http_request_header http_request_content_type __http_request_header
= {
970 .name
= "Content-Type",
971 .format
= http_format_content_type
,
975 * Construct HTTP "Content-Length" header
977 * @v http HTTP transaction
979 * @v len Length of buffer
980 * @ret len Length of header value, or negative error
982 static int http_format_content_length ( struct http_transaction
*http
,
983 char *buf
, size_t len
) {
985 /* Construct content length, if applicable */
986 if ( http
->request
.content
.len
) {
987 return snprintf ( buf
, len
, "%zd", http
->request
.content
.len
);
993 /** HTTP "Content-Length" header */
994 struct http_request_header http_request_content_length __http_request_header
= {
995 .name
= "Content-Length",
996 .format
= http_format_content_length
,
1000 * Construct HTTP "Accept-Encoding" header
1002 * @v http HTTP transaction
1004 * @v len Length of buffer
1005 * @ret len Length of header value, or negative error
1007 static int http_format_accept_encoding ( struct http_transaction
*http
,
1008 char *buf
, size_t len
) {
1009 struct http_content_encoding
*encoding
;
1010 const char *sep
= "";
1013 /* Construct list of content encodings */
1014 for_each_table_entry ( encoding
, HTTP_CONTENT_ENCODINGS
) {
1015 if ( encoding
->supported
&& ( ! encoding
->supported ( http
) ) )
1017 used
+= ssnprintf ( ( buf
+ used
), ( len
- used
),
1018 "%s%s", sep
, encoding
->name
);
1025 /** HTTP "Accept-Encoding" header */
1026 struct http_request_header http_request_accept_encoding __http_request_header
={
1027 .name
= "Accept-Encoding",
1028 .format
= http_format_accept_encoding
,
1034 * @v http HTTP transaction
1035 * @ret rc Return status code
1037 static int http_tx_request ( struct http_transaction
*http
) {
1038 struct io_buffer
*iobuf
;
1043 /* Calculate request length */
1044 len
= http_format_headers ( http
, NULL
, 0 );
1047 DBGC ( http
, "HTTP %p could not construct request: %s\n",
1048 http
, strerror ( rc
) );
1052 /* Allocate I/O buffer */
1053 iobuf
= alloc_iob ( len
+ 1 /* NUL */ + http
->request
.content
.len
);
1059 /* Construct request */
1060 check_len
= http_format_headers ( http
, iob_put ( iobuf
, len
),
1061 ( len
+ 1 /* NUL */ ) );
1062 assert ( check_len
== len
);
1063 memcpy ( iob_put ( iobuf
, http
->request
.content
.len
),
1064 http
->request
.content
.data
, http
->request
.content
.len
);
1066 /* Deliver request */
1067 if ( ( rc
= xfer_deliver_iob ( &http
->conn
,
1068 iob_disown ( iobuf
) ) ) != 0 ) {
1069 DBGC ( http
, "HTTP %p could not deliver request: %s\n",
1070 http
, strerror ( rc
) );
1074 /* Clear any previous response */
1075 empty_line_buffer ( &http
->response
.headers
);
1076 memset ( &http
->response
, 0, sizeof ( http
->response
) );
1078 /* Move to response headers state */
1079 http
->state
= &http_headers
;
1090 /** HTTP request state */
1091 static struct http_state http_request
= {
1092 .tx
= http_tx_request
,
1093 .close
= http_close_error
,
1096 /******************************************************************************
1100 ******************************************************************************
1104 * Parse HTTP status line
1106 * @v http HTTP transaction
1107 * @v line Status line
1108 * @ret rc Return status code
1110 static int http_parse_status ( struct http_transaction
*http
, char *line
) {
1117 DBGC2 ( http
, "HTTP %p RX %s\n", http
, line
);
1119 /* Parse HTTP version */
1120 version
= http_token ( &line
, NULL
);
1121 if ( ( ! version
) || ( strncmp ( version
, "HTTP/", 5 ) != 0 ) ) {
1122 DBGC ( http
, "HTTP %p malformed version \"%s\"\n", http
, line
);
1123 return -EINVAL_STATUS
;
1126 /* Keepalive is enabled by default for anything newer than HTTP/1.0 */
1127 vernum
= ( version
+ 5 /* "HTTP/" (presence already checked) */ );
1128 if ( vernum
[0] == '0' ) {
1129 /* HTTP/0.x : keepalive not enabled by default */
1130 } else if ( strncmp ( vernum
, "1.0", 3 ) == 0 ) {
1131 /* HTTP/1.0 : keepalive not enabled by default */
1133 /* HTTP/1.1 or newer: keepalive enabled by default */
1134 http
->response
.flags
|= HTTP_RESPONSE_KEEPALIVE
;
1137 /* Parse status code */
1139 http
->response
.status
= strtoul ( status
, &endp
, 10 );
1140 if ( *endp
!= ' ' ) {
1141 DBGC ( http
, "HTTP %p malformed status code \"%s\"\n",
1143 return -EINVAL_STATUS
;
1146 /* Convert HTTP status code to iPXE return status code */
1147 if ( status
[0] == '2' ) {
1150 } else if ( status
[0] == '3' ) {
1151 /* 3xx Redirection */
1152 response_rc
= -EXDEV
;
1153 } else if ( http
->response
.status
== 401 ) {
1154 /* 401 Unauthorized */
1155 response_rc
= -EACCES_401
;
1156 } else if ( http
->response
.status
== 403 ) {
1158 response_rc
= -EPERM_403
;
1159 } else if ( http
->response
.status
== 404 ) {
1161 response_rc
= -ENOENT_404
;
1162 } else if ( status
[0] == '4' ) {
1163 /* 4xx Client Error (not already specified) */
1164 response_rc
= -EIO_4XX
;
1165 } else if ( status
[0] == '5' ) {
1166 /* 5xx Server Error */
1167 response_rc
= -EIO_5XX
;
1170 response_rc
= -EIO_OTHER
;
1172 http
->response
.rc
= response_rc
;
1180 * @v http HTTP transaction
1181 * @v line Header line
1182 * @ret rc Return status code
1184 static int http_parse_header ( struct http_transaction
*http
, char *line
) {
1185 struct http_response_header
*header
;
1189 DBGC2 ( http
, "HTTP %p RX %s\n", http
, line
);
1191 /* Extract header name */
1192 sep
= strchr ( line
, ':' );
1194 DBGC ( http
, "HTTP %p malformed header \"%s\"\n", http
, line
);
1195 return -EINVAL_HEADER
;
1199 /* Extract remainder of line */
1201 while ( isspace ( *line
) )
1204 /* Process header, if recognised */
1205 for_each_table_entry ( header
, HTTP_RESPONSE_HEADERS
) {
1206 if ( strcasecmp ( name
, header
->name
) == 0 )
1207 return header
->parse ( http
, line
);
1210 /* Unrecognised headers should be ignored */
1215 * Parse HTTP response headers
1217 * @v http HTTP transaction
1218 * @ret rc Return status code
1220 static int http_parse_headers ( struct http_transaction
*http
) {
1225 /* Get status line */
1226 line
= http
->response
.headers
.data
;
1227 assert ( line
!= NULL
);
1228 next
= ( line
+ strlen ( line
) + 1 /* NUL */ );
1230 /* Parse status line */
1231 if ( ( rc
= http_parse_status ( http
, line
) ) != 0 )
1234 /* Process header lines */
1237 /* Move to next line */
1239 next
= ( line
+ strlen ( line
) + 1 /* NUL */ );
1241 /* Stop on terminating blank line */
1245 /* Process header line */
1246 if ( ( rc
= http_parse_header ( http
, line
) ) != 0 )
1252 * Parse HTTP "Location" header
1254 * @v http HTTP transaction
1255 * @v line Remaining header line
1256 * @ret rc Return status code
1258 static int http_parse_location ( struct http_transaction
*http
, char *line
) {
1260 /* Store location */
1261 http
->response
.location
= line
;
1265 /** HTTP "Location" header */
1266 struct http_response_header http_response_location __http_response_header
= {
1268 .parse
= http_parse_location
,
1272 * Parse HTTP "Transfer-Encoding" header
1274 * @v http HTTP transaction
1275 * @v line Remaining header line
1276 * @ret rc Return status code
1278 static int http_parse_transfer_encoding ( struct http_transaction
*http
,
1280 struct http_transfer_encoding
*encoding
;
1282 /* Check for known transfer encodings */
1283 for_each_table_entry ( encoding
, HTTP_TRANSFER_ENCODINGS
) {
1284 if ( strcasecmp ( line
, encoding
->name
) == 0 ) {
1285 http
->response
.transfer
.encoding
= encoding
;
1290 DBGC ( http
, "HTTP %p unrecognised Transfer-Encoding \"%s\"\n",
1292 return -ENOTSUP_TRANSFER
;
1295 /** HTTP "Transfer-Encoding" header */
1296 struct http_response_header
1297 http_response_transfer_encoding __http_response_header
= {
1298 .name
= "Transfer-Encoding",
1299 .parse
= http_parse_transfer_encoding
,
1303 * Parse HTTP "Connection" header
1305 * @v http HTTP transaction
1306 * @v line Remaining header line
1307 * @ret rc Return status code
1309 static int http_parse_connection ( struct http_transaction
*http
, char *line
) {
1312 /* Check for known connection intentions */
1313 while ( ( token
= http_token ( &line
, NULL
) ) ) {
1314 if ( strcasecmp ( token
, "keep-alive" ) == 0 )
1315 http
->response
.flags
|= HTTP_RESPONSE_KEEPALIVE
;
1316 if ( strcasecmp ( token
, "close" ) == 0 )
1317 http
->response
.flags
&= ~HTTP_RESPONSE_KEEPALIVE
;
1323 /** HTTP "Connection" header */
1324 struct http_response_header http_response_connection __http_response_header
= {
1325 .name
= "Connection",
1326 .parse
= http_parse_connection
,
1330 * Parse HTTP "Content-Length" header
1332 * @v http HTTP transaction
1333 * @v line Remaining header line
1334 * @ret rc Return status code
1336 static int http_parse_content_length ( struct http_transaction
*http
,
1341 http
->response
.content
.len
= strtoul ( line
, &endp
, 10 );
1342 if ( *endp
!= '\0' ) {
1343 DBGC ( http
, "HTTP %p invalid Content-Length \"%s\"\n",
1345 return -EINVAL_CONTENT_LENGTH
;
1348 /* Record that we have a content length (since it may be zero) */
1349 http
->response
.flags
|= HTTP_RESPONSE_CONTENT_LEN
;
1354 /** HTTP "Content-Length" header */
1355 struct http_response_header
1356 http_response_content_length __http_response_header
= {
1357 .name
= "Content-Length",
1358 .parse
= http_parse_content_length
,
1362 * Parse HTTP "Content-Encoding" header
1364 * @v http HTTP transaction
1365 * @v line Remaining header line
1366 * @ret rc Return status code
1368 static int http_parse_content_encoding ( struct http_transaction
*http
,
1370 struct http_content_encoding
*encoding
;
1372 /* Check for known content encodings */
1373 for_each_table_entry ( encoding
, HTTP_CONTENT_ENCODINGS
) {
1374 if ( encoding
->supported
&& ( ! encoding
->supported ( http
) ) )
1376 if ( strcasecmp ( line
, encoding
->name
) == 0 ) {
1377 http
->response
.content
.encoding
= encoding
;
1382 /* Some servers (e.g. Apache) have a habit of specifying
1383 * unwarranted content encodings. For example, if Apache
1384 * detects (via /etc/httpd/conf/magic) that a file's contents
1385 * are gzip-compressed, it will set "Content-Encoding: x-gzip"
1386 * regardless of the client's Accept-Encoding header. The
1387 * only viable way to handle such servers is to treat unknown
1388 * content encodings as equivalent to "identity".
1390 DBGC ( http
, "HTTP %p unrecognised Content-Encoding \"%s\"\n",
1395 /** HTTP "Content-Encoding" header */
1396 struct http_response_header
1397 http_response_content_encoding __http_response_header
= {
1398 .name
= "Content-Encoding",
1399 .parse
= http_parse_content_encoding
,
1403 * Parse HTTP "Retry-After" header
1405 * @v http HTTP transaction
1406 * @v line Remaining header line
1407 * @ret rc Return status code
1409 static int http_parse_retry_after ( struct http_transaction
*http
,
1413 /* Try to parse value as a simple number of seconds */
1414 http
->response
.retry_after
= strtoul ( line
, &endp
, 10 );
1415 if ( *endp
!= '\0' ) {
1416 /* For any value which is not a simple number of
1417 * seconds (e.g. a full HTTP date), just retry after a
1418 * fixed delay, since we don't have code able to parse
1421 http
->response
.retry_after
= HTTP_RETRY_SECONDS
;
1422 DBGC ( http
, "HTTP %p cannot understand Retry-After \"%s\"; "
1423 "using %d seconds\n", http
, line
, HTTP_RETRY_SECONDS
);
1426 /* Allow HTTP request to be retried after specified delay */
1427 http
->response
.flags
|= HTTP_RESPONSE_RETRY
;
1432 /** HTTP "Retry-After" header */
1433 struct http_response_header http_response_retry_after __http_response_header
= {
1434 .name
= "Retry-After",
1435 .parse
= http_parse_retry_after
,
1439 * Handle received HTTP headers
1441 * @v http HTTP transaction
1442 * @v iobuf I/O buffer (may be claimed)
1443 * @ret rc Return status code
1445 static int http_rx_headers ( struct http_transaction
*http
,
1446 struct io_buffer
**iobuf
) {
1447 struct http_transfer_encoding
*transfer
;
1448 struct http_content_encoding
*content
;
1452 /* Buffer header line */
1453 if ( ( rc
= http_rx_linebuf ( http
, *iobuf
,
1454 &http
->response
.headers
) ) != 0 )
1457 /* Wait until we see the empty line marking end of headers */
1458 line
= buffered_line ( &http
->response
.headers
);
1459 if ( ( line
== NULL
) || ( line
[0] != '\0' ) )
1462 /* Process headers */
1463 if ( ( rc
= http_parse_headers ( http
) ) != 0 )
1466 /* Initialise content encoding, if applicable */
1467 if ( ( content
= http
->response
.content
.encoding
) &&
1468 ( ( rc
= content
->init ( http
) ) != 0 ) ) {
1469 DBGC ( http
, "HTTP %p could not initialise %s content "
1470 "encoding: %s\n", http
, content
->name
, strerror ( rc
) );
1474 /* Presize receive buffer, if we have a content length */
1475 if ( http
->response
.content
.len
) {
1476 xfer_seek ( &http
->transfer
, http
->response
.content
.len
);
1477 xfer_seek ( &http
->transfer
, 0 );
1480 /* Complete transfer if this is a HEAD request */
1481 if ( http
->request
.method
== &http_head
) {
1482 if ( ( rc
= http_transfer_complete ( http
) ) != 0 )
1487 /* Default to identity transfer encoding, if none specified */
1488 if ( ! http
->response
.transfer
.encoding
)
1489 http
->response
.transfer
.encoding
= &http_transfer_identity
;
1491 /* Move to transfer encoding-specific data state */
1492 transfer
= http
->response
.transfer
.encoding
;
1493 http
->state
= &transfer
->state
;
1495 /* Initialise transfer encoding */
1496 if ( ( rc
= transfer
->init ( http
) ) != 0 ) {
1497 DBGC ( http
, "HTTP %p could not initialise %s transfer "
1498 "encoding: %s\n", http
, transfer
->name
, strerror ( rc
));
1505 /** HTTP response headers state */
1506 static struct http_state http_headers
= {
1507 .rx
= http_rx_headers
,
1508 .close
= http_close_error
,
1511 /******************************************************************************
1513 * Identity transfer encoding
1515 ******************************************************************************
1519 * Initialise transfer encoding
1521 * @v http HTTP transaction
1522 * @ret rc Return status code
1524 static int http_init_transfer_identity ( struct http_transaction
*http
) {
1527 /* Complete transfer immediately if we have a zero content length */
1528 if ( ( http
->response
.flags
& HTTP_RESPONSE_CONTENT_LEN
) &&
1529 ( http
->response
.content
.len
== 0 ) &&
1530 ( ( rc
= http_transfer_complete ( http
) ) != 0 ) )
1537 * Handle received data
1539 * @v http HTTP transaction
1540 * @v iobuf I/O buffer (may be claimed)
1541 * @ret rc Return status code
1543 static int http_rx_transfer_identity ( struct http_transaction
*http
,
1544 struct io_buffer
**iobuf
) {
1545 size_t len
= iob_len ( *iobuf
);
1548 /* Update lengths */
1551 /* Fail if this transfer would overrun the expected content
1554 if ( ( http
->response
.flags
& HTTP_RESPONSE_CONTENT_LEN
) &&
1555 ( http
->len
> http
->response
.content
.len
) ) {
1556 DBGC ( http
, "HTTP %p content length overrun\n", http
);
1557 return -EIO_CONTENT_LENGTH
;
1560 /* Hand off to content encoding */
1561 if ( ( rc
= xfer_deliver_iob ( &http
->transfer
,
1562 iob_disown ( *iobuf
) ) ) != 0 )
1565 /* Complete transfer if we have received the expected content
1568 if ( ( http
->response
.flags
& HTTP_RESPONSE_CONTENT_LEN
) &&
1569 ( http
->len
== http
->response
.content
.len
) &&
1570 ( ( rc
= http_transfer_complete ( http
) ) != 0 ) )
1577 * Handle server connection close
1579 * @v http HTTP transaction
1580 * @v rc Reason for close
1582 static void http_close_transfer_identity ( struct http_transaction
*http
,
1585 /* Fail if any error occurred */
1589 /* Fail if we have a content length (since we would have
1590 * already closed the connection if we had received the
1591 * correct content length).
1593 if ( http
->response
.flags
& HTTP_RESPONSE_CONTENT_LEN
) {
1594 DBGC ( http
, "HTTP %p content length underrun\n", http
);
1595 rc
= EIO_CONTENT_LENGTH
;
1599 /* Indicate that transfer is complete */
1600 if ( ( rc
= http_transfer_complete ( http
) ) != 0 )
1606 http_close ( http
, rc
);
1609 /** Identity transfer encoding */
1610 static struct http_transfer_encoding http_transfer_identity
= {
1612 .init
= http_init_transfer_identity
,
1614 .rx
= http_rx_transfer_identity
,
1615 .close
= http_close_transfer_identity
,
1619 /******************************************************************************
1621 * Chunked transfer encoding
1623 ******************************************************************************
1627 * Initialise transfer encoding
1629 * @v http HTTP transaction
1630 * @ret rc Return status code
1632 static int http_init_transfer_chunked ( struct http_transaction
*http
) {
1635 assert ( http
->remaining
== 0 );
1636 assert ( http
->linebuf
.len
== 0 );
1642 * Handle received chunk length
1644 * @v http HTTP transaction
1645 * @v iobuf I/O buffer (may be claimed)
1646 * @ret rc Return status code
1648 static int http_rx_chunk_len ( struct http_transaction
*http
,
1649 struct io_buffer
**iobuf
) {
1655 /* Receive into temporary line buffer */
1656 if ( ( rc
= http_rx_linebuf ( http
, *iobuf
, &http
->linebuf
) ) != 0 )
1659 /* Wait until we receive a non-empty line */
1660 line
= buffered_line ( &http
->linebuf
);
1661 if ( ( line
== NULL
) || ( line
[0] == '\0' ) )
1664 /* Parse chunk length */
1665 http
->remaining
= strtoul ( line
, &endp
, 16 );
1666 if ( *endp
!= '\0' ) {
1667 DBGC ( http
, "HTTP %p invalid chunk length \"%s\"\n",
1669 return -EINVAL_CHUNK_LENGTH
;
1672 /* Empty line buffer */
1673 empty_line_buffer ( &http
->linebuf
);
1675 /* Update expected length */
1676 len
= ( http
->len
+ http
->remaining
);
1677 xfer_seek ( &http
->transfer
, len
);
1678 xfer_seek ( &http
->transfer
, http
->len
);
1680 /* If chunk length is zero, then move to response trailers state */
1681 if ( ! http
->remaining
)
1682 http
->state
= &http_trailers
;
1688 * Handle received chunk data
1690 * @v http HTTP transaction
1691 * @v iobuf I/O buffer (may be claimed)
1692 * @ret rc Return status code
1694 static int http_rx_chunk_data ( struct http_transaction
*http
,
1695 struct io_buffer
**iobuf
) {
1696 struct io_buffer
*payload
;
1701 /* In the common case of a final chunk in a packet which also
1702 * includes the terminating CRLF, strip the terminating CRLF
1703 * (which we would ignore anyway) and hence avoid
1704 * unnecessarily copying the data.
1706 if ( iob_len ( *iobuf
) == ( http
->remaining
+ 2 /* CRLF */ ) ) {
1707 crlf
= ( (*iobuf
)->data
+ http
->remaining
);
1708 if ( ( crlf
[0] == '\r' ) && ( crlf
[1] == '\n' ) )
1709 iob_unput ( (*iobuf
), 2 /* CRLF */ );
1711 len
= iob_len ( *iobuf
);
1713 /* Use whole/partial buffer as applicable */
1714 if ( len
<= http
->remaining
) {
1716 /* Whole buffer is to be consumed: decrease remaining
1717 * length and use original I/O buffer as payload.
1719 payload
= iob_disown ( *iobuf
);
1721 http
->remaining
-= len
;
1725 /* Partial buffer is to be consumed: copy data to a
1726 * temporary I/O buffer.
1728 payload
= alloc_iob ( http
->remaining
);
1733 memcpy ( iob_put ( payload
, http
->remaining
), (*iobuf
)->data
,
1735 iob_pull ( *iobuf
, http
->remaining
);
1736 http
->len
+= http
->remaining
;
1737 http
->remaining
= 0;
1740 /* Hand off to content encoding */
1741 if ( ( rc
= xfer_deliver_iob ( &http
->transfer
,
1742 iob_disown ( payload
) ) ) != 0 )
1748 assert ( payload
== NULL
);
1753 * Handle received chunked data
1755 * @v http HTTP transaction
1756 * @v iobuf I/O buffer (may be claimed)
1757 * @ret rc Return status code
1759 static int http_rx_transfer_chunked ( struct http_transaction
*http
,
1760 struct io_buffer
**iobuf
) {
1762 /* Handle as chunk length or chunk data as appropriate */
1763 if ( http
->remaining
) {
1764 return http_rx_chunk_data ( http
, iobuf
);
1766 return http_rx_chunk_len ( http
, iobuf
);
1770 /** Chunked transfer encoding */
1771 struct http_transfer_encoding http_transfer_chunked __http_transfer_encoding
= {
1773 .init
= http_init_transfer_chunked
,
1775 .rx
= http_rx_transfer_chunked
,
1776 .close
= http_close_error
,
1780 /******************************************************************************
1784 ******************************************************************************
1788 * Handle received HTTP trailer
1790 * @v http HTTP transaction
1791 * @v iobuf I/O buffer (may be claimed)
1792 * @ret rc Return status code
1794 static int http_rx_trailers ( struct http_transaction
*http
,
1795 struct io_buffer
**iobuf
) {
1799 /* Buffer trailer line */
1800 if ( ( rc
= http_rx_linebuf ( http
, *iobuf
, &http
->linebuf
) ) != 0 )
1803 /* Wait until we see the empty line marking end of trailers */
1804 line
= buffered_line ( &http
->linebuf
);
1805 if ( ( line
== NULL
) || ( line
[0] != '\0' ) )
1808 /* Empty line buffer */
1809 empty_line_buffer ( &http
->linebuf
);
1811 /* Transfer is complete */
1812 if ( ( rc
= http_transfer_complete ( http
) ) != 0 )
1818 /** HTTP response trailers state */
1819 static struct http_state http_trailers
= {
1820 .rx
= http_rx_trailers
,
1821 .close
= http_close_error
,
1824 /******************************************************************************
1826 * Simple URI openers
1828 ******************************************************************************
1832 * Construct HTTP parameter list
1834 * @v params Parameter list
1835 * @v buf Buffer to contain HTTP POST parameters
1836 * @v len Length of buffer
1837 * @ret len Length of parameter list (excluding terminating NUL)
1839 static size_t http_params ( struct parameters
*params
, char *buf
, size_t len
) {
1840 struct parameter
*param
;
1841 ssize_t remaining
= len
;
1844 /* Add each parameter in the form "key=value", joined with "&" */
1846 for_each_param ( param
, params
) {
1848 /* Add the "&", if applicable */
1850 if ( remaining
> 0 )
1857 /* URI-encode the key */
1858 frag_len
= uri_encode_string ( 0, param
->key
, buf
, remaining
);
1861 remaining
-= frag_len
;
1864 if ( remaining
> 0 )
1870 /* URI-encode the value */
1871 frag_len
= uri_encode_string ( 0, param
->value
, buf
, remaining
);
1874 remaining
-= frag_len
;
1877 /* Ensure string is NUL-terminated even if no parameters are present */
1878 if ( remaining
> 0 )
1885 * Open HTTP transaction for simple GET URI
1887 * @v xfer Data transfer interface
1888 * @v uri Request URI
1889 * @ret rc Return status code
1891 static int http_open_get_uri ( struct interface
*xfer
, struct uri
*uri
) {
1893 return http_open ( xfer
, &http_get
, uri
, NULL
, NULL
);
1897 * Open HTTP transaction for simple POST URI
1899 * @v xfer Data transfer interface
1900 * @v uri Request URI
1901 * @ret rc Return status code
1903 static int http_open_post_uri ( struct interface
*xfer
, struct uri
*uri
) {
1904 struct parameters
*params
= uri
->params
;
1905 struct http_request_content content
;
1911 /* Calculate length of parameter list */
1912 len
= http_params ( params
, NULL
, 0 );
1914 /* Allocate temporary parameter list */
1915 data
= zalloc ( len
+ 1 /* NUL */ );
1921 /* Construct temporary parameter list */
1922 check_len
= http_params ( params
, data
, ( len
+ 1 /* NUL */ ) );
1923 assert ( check_len
== len
);
1925 /* Construct request content */
1926 content
.type
= "application/x-www-form-urlencoded";
1927 content
.data
= data
;
1930 /* Open HTTP transaction */
1931 if ( ( rc
= http_open ( xfer
, &http_post
, uri
, NULL
, &content
) ) != 0 )
1941 * Open HTTP transaction for simple URI
1943 * @v xfer Data transfer interface
1944 * @v uri Request URI
1945 * @ret rc Return status code
1947 int http_open_uri ( struct interface
*xfer
, struct uri
*uri
) {
1949 /* Open GET/POST URI as applicable */
1950 if ( uri
->params
) {
1951 return http_open_post_uri ( xfer
, uri
);
1953 return http_open_get_uri ( xfer
, uri
);
1957 /* Drag in HTTP extensions */
1958 REQUIRING_SYMBOL ( http_open
);
1959 REQUIRE_OBJECT ( config_http
);