Browse Source

[http] Support read-only HTTP block devices

Provide support for HTTP range requests, and expose this functionality
via the iPXE block device API.  This allows SAN booting from a root
path such as:

    sanboot http://boot.ipxe.org/freedos/fdfullcd.iso

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 13 years ago
parent
commit
2988b26653
1 changed files with 308 additions and 59 deletions
  1. 308
    59
      src/net/tcp/http.c

+ 308
- 59
src/net/tcp/http.c View File

44
 #include <ipxe/linebuf.h>
44
 #include <ipxe/linebuf.h>
45
 #include <ipxe/features.h>
45
 #include <ipxe/features.h>
46
 #include <ipxe/base64.h>
46
 #include <ipxe/base64.h>
47
+#include <ipxe/blockdev.h>
48
+#include <ipxe/acpi.h>
47
 #include <ipxe/http.h>
49
 #include <ipxe/http.h>
48
 
50
 
49
 FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
51
 FEATURE ( FEATURE_PROTOCOL, "HTTP", DHCP_EB_FEATURE_HTTP, 1 );
50
 
52
 
51
-/** HTTP transmission state */
52
-enum http_tx_state {
53
-	HTTP_TX_REQUEST = 0,
54
-	HTTP_TX_DONE,
53
+/** Block size used for HTTP block device request */
54
+#define HTTP_BLKSIZE 512
55
+
56
+/** HTTP flags */
57
+enum http_flags {
58
+	/** Request is waiting to be transmitted */
59
+	HTTP_TX_PENDING = 0x0001,
60
+	/** Fetch header only */
61
+	HTTP_HEAD_ONLY = 0x0002,
62
+	/** Keep connection alive */
63
+	HTTP_KEEPALIVE = 0x0004,
55
 };
64
 };
56
 
65
 
57
 /** HTTP receive state */
66
 /** HTTP receive state */
61
 	HTTP_RX_CHUNK_LEN,
70
 	HTTP_RX_CHUNK_LEN,
62
 	HTTP_RX_DATA,
71
 	HTTP_RX_DATA,
63
 	HTTP_RX_TRAILER,
72
 	HTTP_RX_TRAILER,
73
+	HTTP_RX_IDLE,
64
 	HTTP_RX_DEAD,
74
 	HTTP_RX_DEAD,
65
 };
75
 };
66
 
76
 
73
 	struct refcnt refcnt;
83
 	struct refcnt refcnt;
74
 	/** Data transfer interface */
84
 	/** Data transfer interface */
75
 	struct interface xfer;
85
 	struct interface xfer;
86
+	/** Partial transfer interface */
87
+	struct interface partial;
76
 
88
 
77
 	/** URI being fetched */
89
 	/** URI being fetched */
78
 	struct uri *uri;
90
 	struct uri *uri;
79
 	/** Transport layer interface */
91
 	/** Transport layer interface */
80
 	struct interface socket;
92
 	struct interface socket;
81
 
93
 
94
+	/** Flags */
95
+	unsigned int flags;
96
+	/** Starting offset of partial transfer (if applicable) */
97
+	size_t partial_start;
98
+	/** Length of partial transfer (if applicable) */
99
+	size_t partial_len;
100
+
82
 	/** TX process */
101
 	/** TX process */
83
 	struct process process;
102
 	struct process process;
84
-	/** TX state */
85
-	enum http_tx_state tx_state;
86
 
103
 
87
-	/** HTTP response code */
88
-	unsigned int response;
89
-	/** HTTP Content-Length */
90
-	size_t content_length;
91
-	/** HTTP is using Transfer-Encoding: chunked */
92
-	int chunked;
93
-	/** Current chunk length */
94
-	size_t chunk_len;
95
-	/** Received length */
96
-	size_t rx_len;
97
 	/** RX state */
104
 	/** RX state */
98
 	enum http_rx_state rx_state;
105
 	enum http_rx_state rx_state;
106
+	/** Received length */
107
+	size_t rx_len;
108
+	/** Length remaining (or 0 if unknown) */
109
+	size_t remaining;
110
+	/** HTTP is using Transfer-Encoding: chunked */
111
+	int chunked;
112
+	/** Current chunk length remaining (if applicable) */
113
+	size_t chunk_remaining;
99
 	/** Line buffer for received header lines */
114
 	/** Line buffer for received header lines */
100
 	struct line_buffer linebuf;
115
 	struct line_buffer linebuf;
116
+	/** Receive data buffer (if applicable) */
117
+	userptr_t rx_buffer;
101
 };
118
 };
102
 
119
 
103
 /**
120
 /**
115
 };
132
 };
116
 
133
 
117
 /**
134
 /**
118
- * Mark HTTP request as complete
135
+ * Close HTTP request
119
  *
136
  *
120
  * @v http		HTTP request
137
  * @v http		HTTP request
121
  * @v rc		Return status code
138
  * @v rc		Return status code
122
  */
139
  */
123
-static void http_done ( struct http_request *http, int rc ) {
140
+static void http_close ( struct http_request *http, int rc ) {
124
 
141
 
125
 	/* Prevent further processing of any current packet */
142
 	/* Prevent further processing of any current packet */
126
 	http->rx_state = HTTP_RX_DEAD;
143
 	http->rx_state = HTTP_RX_DEAD;
128
 	/* If we had a Content-Length, and the received content length
145
 	/* If we had a Content-Length, and the received content length
129
 	 * isn't correct, flag an error
146
 	 * isn't correct, flag an error
130
 	 */
147
 	 */
131
-	if ( http->content_length &&
132
-	     ( http->content_length != http->rx_len ) ) {
148
+	if ( http->remaining != 0 ) {
133
 		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
149
 		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
134
-		       http, http->rx_len, http->content_length );
135
-		rc = -EIO;
150
+		       http, http->rx_len, ( http->rx_len + http->remaining ) );
151
+		if ( rc == 0 )
152
+			rc = -EIO;
136
 	}
153
 	}
137
 
154
 
138
 	/* Remove process */
155
 	/* Remove process */
140
 
157
 
141
 	/* Close all data transfer interfaces */
158
 	/* Close all data transfer interfaces */
142
 	intf_shutdown ( &http->socket, rc );
159
 	intf_shutdown ( &http->socket, rc );
160
+	intf_shutdown ( &http->partial, rc );
143
 	intf_shutdown ( &http->xfer, rc );
161
 	intf_shutdown ( &http->xfer, rc );
144
 }
162
 }
145
 
163
 
164
+/**
165
+ * Mark HTTP request as completed successfully
166
+ *
167
+ * @v http		HTTP request
168
+ */
169
+static void http_done ( struct http_request *http ) {
170
+
171
+	/* If we had a Content-Length, and the received content length
172
+	 * isn't correct, force an error
173
+	 */
174
+	if ( http->remaining != 0 ) {
175
+		http_close ( http, -EIO );
176
+		return;
177
+	}
178
+
179
+	/* Enter idle state */
180
+	http->rx_state = HTTP_RX_IDLE;
181
+	http->rx_len = 0;
182
+	assert ( http->remaining == 0 );
183
+	assert ( http->chunked == 0 );
184
+	assert ( http->chunk_remaining == 0 );
185
+
186
+	/* Close partial transfer interface */
187
+	intf_restart ( &http->partial, 0 );
188
+
189
+	/* Close everything unless we are keeping the connection alive */
190
+	if ( ! ( http->flags & HTTP_KEEPALIVE ) )
191
+		http_close ( http, 0 );
192
+}
193
+
146
 /**
194
 /**
147
  * Convert HTTP response code to return status code
195
  * Convert HTTP response code to return status code
148
  *
196
  *
152
 static int http_response_to_rc ( unsigned int response ) {
200
 static int http_response_to_rc ( unsigned int response ) {
153
 	switch ( response ) {
201
 	switch ( response ) {
154
 	case 200:
202
 	case 200:
203
+	case 206:
155
 	case 301:
204
 	case 301:
156
 	case 302:
205
 	case 302:
157
 		return 0;
206
 		return 0;
175
  */
224
  */
176
 static int http_rx_response ( struct http_request *http, char *response ) {
225
 static int http_rx_response ( struct http_request *http, char *response ) {
177
 	char *spc;
226
 	char *spc;
227
+	unsigned int code;
178
 	int rc;
228
 	int rc;
179
 
229
 
180
 	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
230
 	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
187
 	spc = strchr ( response, ' ' );
237
 	spc = strchr ( response, ' ' );
188
 	if ( ! spc )
238
 	if ( ! spc )
189
 		return -EIO;
239
 		return -EIO;
190
-	http->response = strtoul ( spc, NULL, 10 );
191
-	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
240
+	code = strtoul ( spc, NULL, 10 );
241
+	if ( ( rc = http_response_to_rc ( code ) ) != 0 )
192
 		return rc;
242
 		return rc;
193
 
243
 
194
 	/* Move to received headers */
244
 	/* Move to received headers */
227
  */
277
  */
228
 static int http_rx_content_length ( struct http_request *http,
278
 static int http_rx_content_length ( struct http_request *http,
229
 				    const char *value ) {
279
 				    const char *value ) {
280
+	struct block_device_capacity capacity;
281
+	size_t content_len;
230
 	char *endp;
282
 	char *endp;
231
 
283
 
232
-	http->content_length = strtoul ( value, &endp, 10 );
284
+	/* Parse content length */
285
+	content_len = strtoul ( value, &endp, 10 );
233
 	if ( *endp != '\0' ) {
286
 	if ( *endp != '\0' ) {
234
 		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
287
 		DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
235
 		       http, value );
288
 		       http, value );
236
 		return -EIO;
289
 		return -EIO;
237
 	}
290
 	}
238
 
291
 
292
+	/* If we already have an expected content length, and this
293
+	 * isn't it, then complain
294
+	 */
295
+	if ( http->remaining && ( http->remaining != content_len ) ) {
296
+		DBGC ( http, "HTTP %p incorrect Content-Length %zd (expected "
297
+		       "%zd)\n", http, content_len, http->remaining );
298
+		return -EIO;
299
+	}
300
+	if ( ! ( http->flags & HTTP_HEAD_ONLY ) )
301
+		http->remaining = content_len;
302
+
239
 	/* Use seek() to notify recipient of filesize */
303
 	/* Use seek() to notify recipient of filesize */
240
-	xfer_seek ( &http->xfer, http->content_length );
304
+	xfer_seek ( &http->xfer, http->remaining );
241
 	xfer_seek ( &http->xfer, 0 );
305
 	xfer_seek ( &http->xfer, 0 );
242
 
306
 
307
+	/* Report block device capacity if applicable */
308
+	if ( http->flags & HTTP_HEAD_ONLY ) {
309
+		capacity.blocks = ( content_len / HTTP_BLKSIZE );
310
+		capacity.blksize = HTTP_BLKSIZE;
311
+		capacity.max_count = -1U;
312
+		block_capacity ( &http->partial, &capacity );
313
+	}
243
 	return 0;
314
 	return 0;
244
 }
315
 }
245
 
316
 
309
 	/* An empty header line marks the end of this phase */
380
 	/* An empty header line marks the end of this phase */
310
 	if ( ! header[0] ) {
381
 	if ( ! header[0] ) {
311
 		empty_line_buffer ( &http->linebuf );
382
 		empty_line_buffer ( &http->linebuf );
312
-		if ( http->rx_state == HTTP_RX_HEADER ) {
383
+		if ( ( http->rx_state == HTTP_RX_HEADER ) &&
384
+		     ( ! ( http->flags & HTTP_HEAD_ONLY ) ) ) {
313
 			DBGC ( http, "HTTP %p start of data\n", http );
385
 			DBGC ( http, "HTTP %p start of data\n", http );
314
 			http->rx_state = ( http->chunked ?
386
 			http->rx_state = ( http->chunked ?
315
 					   HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
387
 					   HTTP_RX_CHUNK_LEN : HTTP_RX_DATA );
316
 			return 0;
388
 			return 0;
317
 		} else {
389
 		} else {
318
 			DBGC ( http, "HTTP %p end of trailer\n", http );
390
 			DBGC ( http, "HTTP %p end of trailer\n", http );
319
-			http_done ( http, 0 );
391
+			http_done ( http );
320
 			return 0;
392
 			return 0;
321
 		}
393
 		}
322
 	}
394
 	}
358
 		return 0;
430
 		return 0;
359
 
431
 
360
 	/* Parse chunk length */
432
 	/* Parse chunk length */
361
-	http->chunk_len = strtoul ( length, &endp, 16 );
433
+	http->chunk_remaining = strtoul ( length, &endp, 16 );
362
 	if ( *endp != '\0' ) {
434
 	if ( *endp != '\0' ) {
363
 		DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
435
 		DBGC ( http, "HTTP %p invalid chunk length \"%s\"\n",
364
 		       http, length );
436
 		       http, length );
366
 	}
438
 	}
367
 
439
 
368
 	/* Terminate chunked encoding if applicable */
440
 	/* Terminate chunked encoding if applicable */
369
-	if ( http->chunk_len == 0 ) {
441
+	if ( http->chunk_remaining == 0 ) {
370
 		DBGC ( http, "HTTP %p end of chunks\n", http );
442
 		DBGC ( http, "HTTP %p end of chunks\n", http );
371
 		http->chunked = 0;
443
 		http->chunked = 0;
372
 		http->rx_state = HTTP_RX_TRAILER;
444
 		http->rx_state = HTTP_RX_TRAILER;
375
 
447
 
376
 	/* Use seek() to notify recipient of new filesize */
448
 	/* Use seek() to notify recipient of new filesize */
377
 	DBGC ( http, "HTTP %p start of chunk of length %zd\n",
449
 	DBGC ( http, "HTTP %p start of chunk of length %zd\n",
378
-	       http, http->chunk_len );
379
-	xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_len ) );
450
+	       http, http->chunk_remaining );
451
+	xfer_seek ( &http->xfer, ( http->rx_len + http->chunk_remaining ) );
380
 	xfer_seek ( &http->xfer, http->rx_len );
452
 	xfer_seek ( &http->xfer, http->rx_len );
381
 
453
 
382
 	/* Start receiving data */
454
 	/* Start receiving data */
422
 	int rc = 0;
494
 	int rc = 0;
423
 
495
 
424
 	while ( iobuf && iob_len ( iobuf ) ) {
496
 	while ( iobuf && iob_len ( iobuf ) ) {
497
+
425
 		switch ( http->rx_state ) {
498
 		switch ( http->rx_state ) {
499
+		case HTTP_RX_IDLE:
500
+			/* Receiving any data in this state is an error */
501
+			DBGC ( http, "HTTP %p received %zd bytes while %s\n",
502
+			       http, iob_len ( iobuf ),
503
+			       ( ( http->rx_state == HTTP_RX_IDLE ) ?
504
+				 "idle" : "dead" ) );
505
+			rc = -EPROTO;
506
+			goto done;
426
 		case HTTP_RX_DEAD:
507
 		case HTTP_RX_DEAD:
427
 			/* Do no further processing */
508
 			/* Do no further processing */
428
 			goto done;
509
 			goto done;
429
 		case HTTP_RX_DATA:
510
 		case HTTP_RX_DATA:
430
 			/* Pass received data to caller */
511
 			/* Pass received data to caller */
431
 			data_len = iob_len ( iobuf );
512
 			data_len = iob_len ( iobuf );
432
-			if ( http->chunk_len && ( http->chunk_len < data_len )){
433
-				data_len = http->chunk_len;
513
+			if ( http->chunk_remaining &&
514
+			     ( http->chunk_remaining < data_len ) ) {
515
+				data_len = http->chunk_remaining;
516
+			}
517
+			if ( http->remaining &&
518
+			     ( http->remaining < data_len ) ) {
519
+				data_len = http->remaining;
520
+			}
521
+			if ( http->rx_buffer != UNULL ) {
522
+				/* Copy to partial transfer buffer */
523
+				copy_to_user ( http->rx_buffer, http->rx_len,
524
+					       iobuf->data, data_len );
525
+				iob_pull ( iobuf, data_len );
526
+			} else if ( data_len < iob_len ( iobuf ) ) {
527
+				/* Deliver partial buffer as raw data */
434
 				rc = xfer_deliver_raw ( &http->xfer,
528
 				rc = xfer_deliver_raw ( &http->xfer,
435
 							iobuf->data, data_len );
529
 							iobuf->data, data_len );
436
 				iob_pull ( iobuf, data_len );
530
 				iob_pull ( iobuf, data_len );
531
+				if ( rc != 0 )
532
+					goto done;
437
 			} else {
533
 			} else {
438
-				rc = xfer_deliver_iob ( &http->xfer,
439
-							iob_disown ( iobuf ) );
534
+				/* Deliver whole I/O buffer */
535
+				if ( ( rc = xfer_deliver_iob ( &http->xfer,
536
+						 iob_disown ( iobuf ) ) ) != 0 )
537
+					goto done;
440
 			}
538
 			}
441
-			if ( rc != 0 )
442
-				goto done;
443
-			if ( http->chunk_len ) {
444
-				http->chunk_len -= data_len;
445
-				if ( http->chunk_len == 0 )
539
+			http->rx_len += data_len;
540
+			if ( http->chunk_remaining ) {
541
+				http->chunk_remaining -= data_len;
542
+				if ( http->chunk_remaining == 0 )
446
 					http->rx_state = HTTP_RX_CHUNK_LEN;
543
 					http->rx_state = HTTP_RX_CHUNK_LEN;
447
 			}
544
 			}
448
-			http->rx_len += data_len;
449
-			if ( http->content_length &&
450
-			     ( http->rx_len >= http->content_length ) ) {
451
-				http_done ( http, 0 );
452
-				goto done;
545
+			if ( http->remaining ) {
546
+				http->remaining -= data_len;
547
+				if ( ( http->remaining == 0 ) &&
548
+				     ( http->rx_state == HTTP_RX_DATA ) ) {
549
+					http_done ( http );
550
+				}
453
 			}
551
 			}
454
 			break;
552
 			break;
455
 		case HTTP_RX_RESPONSE:
553
 		case HTTP_RX_RESPONSE:
483
 
581
 
484
  done:
582
  done:
485
 	if ( rc )
583
 	if ( rc )
486
-		http_done ( http, rc );
584
+		http_close ( http, rc );
487
 	free_iob ( iobuf );
585
 	free_iob ( iobuf );
488
 	return rc;
586
 	return rc;
489
 }
587
 }
490
 
588
 
589
+/**
590
+ * Check HTTP socket flow control window
591
+ *
592
+ * @v http		HTTP request
593
+ * @ret len		Length of window
594
+ */
595
+static size_t http_socket_window ( struct http_request *http __unused ) {
596
+
597
+	/* Window is always open.  This is to prevent TCP from
598
+	 * stalling if our parent window is not currently open.
599
+	 */
600
+	return ( ~( ( size_t ) 0 ) );
601
+}
602
+
491
 /**
603
 /**
492
  * HTTP process
604
  * HTTP process
493
  *
605
  *
507
 	int request_len = unparse_uri ( NULL, 0, http->uri,
619
 	int request_len = unparse_uri ( NULL, 0, http->uri,
508
 					URI_PATH_BIT | URI_QUERY_BIT );
620
 					URI_PATH_BIT | URI_QUERY_BIT );
509
 	char request[ request_len + 1 /* NUL */ ];
621
 	char request[ request_len + 1 /* NUL */ ];
622
+	char range[48]; /* Enough for two 64-bit integers in decimal */
623
+	int partial;
510
 
624
 
511
 	/* Do nothing if we have already transmitted the request */
625
 	/* Do nothing if we have already transmitted the request */
512
-	if ( http->tx_state != HTTP_TX_REQUEST )
626
+	if ( ! ( http->flags & HTTP_TX_PENDING ) )
513
 		return;
627
 		return;
514
 
628
 
515
 	/* Do nothing until socket is ready */
629
 	/* Do nothing until socket is ready */
530
 		base64_encode ( user_pw, user_pw_len, user_pw_base64 );
644
 		base64_encode ( user_pw, user_pw_len, user_pw_base64 );
531
 	}
645
 	}
532
 
646
 
647
+	/* Force a HEAD request if we have nowhere to send any received data */
648
+	if ( ( xfer_window ( &http->xfer ) == 0 ) &&
649
+	     ( http->rx_buffer == UNULL ) ) {
650
+		http->flags |= ( HTTP_HEAD_ONLY | HTTP_KEEPALIVE );
651
+	}
652
+
653
+	/* Determine type of request */
654
+	partial = ( http->partial_len != 0 );
655
+	snprintf ( range, sizeof ( range ), "%d-%d", http->partial_start,
656
+		   ( http->partial_start + http->partial_len - 1 ) );
657
+
533
 	/* Mark request as transmitted */
658
 	/* Mark request as transmitted */
534
-	http->tx_state = HTTP_TX_DONE;
659
+	http->flags &= ~HTTP_TX_PENDING;
535
 
660
 
536
 	/* Send GET request */
661
 	/* Send GET request */
537
 	if ( ( rc = xfer_printf ( &http->socket,
662
 	if ( ( rc = xfer_printf ( &http->socket,
538
-				  "GET %s%s HTTP/1.1\r\n"
663
+				  "%s %s%s HTTP/1.1\r\n"
539
 				  "User-Agent: iPXE/" VERSION "\r\n"
664
 				  "User-Agent: iPXE/" VERSION "\r\n"
540
-				  "%s%s%s"
541
 				  "Host: %s\r\n"
665
 				  "Host: %s\r\n"
666
+				  "%s%s%s%s%s%s%s"
542
 				  "\r\n",
667
 				  "\r\n",
543
-				  http->uri->path ? "" : "/",
544
-				  request,
668
+				  ( ( http->flags & HTTP_HEAD_ONLY ) ?
669
+				    "HEAD" : "GET" ),
670
+				  ( http->uri->path ? "" : "/" ),
671
+				  request, host,
672
+				  ( ( http->flags & HTTP_KEEPALIVE ) ?
673
+				    "Connection: Keep-Alive\r\n" : "" ),
674
+				  ( partial ? "Range: bytes=" : "" ),
675
+				  ( partial ? range : "" ),
676
+				  ( partial ? "\r\n" : "" ),
545
 				  ( user ?
677
 				  ( user ?
546
 				    "Authorization: Basic " : "" ),
678
 				    "Authorization: Basic " : "" ),
547
 				  ( user ? user_pw_base64 : "" ),
679
 				  ( user ? user_pw_base64 : "" ),
548
-				  ( user ? "\r\n" : "" ),
549
-				  host ) ) != 0 ) {
550
-		http_done ( http, rc );
680
+				  ( user ? "\r\n" : "" ) ) ) != 0 ) {
681
+		http_close ( http, rc );
551
 	}
682
 	}
552
 }
683
 }
553
 
684
 
685
+/**
686
+ * Check HTTP data transfer flow control window
687
+ *
688
+ * @v http		HTTP request
689
+ * @ret len		Length of window
690
+ */
691
+static size_t http_xfer_window ( struct http_request *http ) {
692
+
693
+	/* New block commands may be issued only when we are idle */
694
+	return ( ( http->rx_state == HTTP_RX_IDLE ) ? 1 : 0 );
695
+}
696
+
697
+/**
698
+ * Initiate HTTP partial read
699
+ *
700
+ * @v http		HTTP request
701
+ * @v partial		Partial transfer interface
702
+ * @v offset		Starting offset
703
+ * @v buffer		Data buffer
704
+ * @v len		Length
705
+ * @ret rc		Return status code
706
+ */
707
+static int http_partial_read ( struct http_request *http,
708
+			       struct interface *partial,
709
+			       size_t offset, userptr_t buffer, size_t len ) {
710
+
711
+	/* Sanity check */
712
+	if ( http_xfer_window ( http ) == 0 )
713
+		return -EBUSY;
714
+
715
+	/* Initialise partial transfer parameters */
716
+	http->rx_buffer = buffer;
717
+	http->partial_start = offset;
718
+	http->partial_len = len;
719
+	http->remaining = len;
720
+
721
+	/* Schedule request */
722
+	http->rx_state = HTTP_RX_RESPONSE;
723
+	http->flags = ( HTTP_TX_PENDING | HTTP_KEEPALIVE );
724
+	if ( ! len )
725
+		http->flags |= HTTP_HEAD_ONLY;
726
+	process_add ( &http->process );
727
+
728
+	/* Attach to parent interface and return */
729
+	intf_plug_plug ( &http->partial, partial );
730
+
731
+	return 0;
732
+}
733
+
734
+/**
735
+ * Issue HTTP block device read
736
+ *
737
+ * @v http		HTTP request
738
+ * @v block		Block data interface
739
+ * @v lba		Starting logical block address
740
+ * @v count		Number of blocks to transfer
741
+ * @v buffer		Data buffer
742
+ * @v len		Length of data buffer
743
+ * @ret rc		Return status code
744
+ */
745
+static int http_block_read ( struct http_request *http,
746
+			     struct interface *block,
747
+			     uint64_t lba, unsigned int count,
748
+			     userptr_t buffer, size_t len __unused ) {
749
+
750
+	return http_partial_read ( http, block, ( lba * HTTP_BLKSIZE ),
751
+				   buffer, ( count * HTTP_BLKSIZE ) );
752
+}
753
+
754
+/**
755
+ * Read HTTP block device capacity
756
+ *
757
+ * @v http		HTTP request
758
+ * @v block		Block data interface
759
+ * @ret rc		Return status code
760
+ */
761
+static int http_block_read_capacity ( struct http_request *http,
762
+				      struct interface *block ) {
763
+
764
+	return http_partial_read ( http, block, 0, 0, 0 );
765
+}
766
+
767
+/**
768
+ * Describe HTTP device in an ACPI table
769
+ *
770
+ * @v http		HTTP request
771
+ * @v acpi		ACPI table
772
+ * @v len		Length of ACPI table
773
+ * @ret rc		Return status code
774
+ */
775
+static int http_acpi_describe ( struct http_request *http,
776
+				struct acpi_description_header *acpi,
777
+				size_t len ) {
778
+
779
+	DBGC ( http, "HTTP %p cannot yet describe device in an ACPI table\n",
780
+	       http );
781
+	( void ) acpi;
782
+	( void ) len;
783
+	return 0;
784
+}
785
+
554
 /** HTTP socket interface operations */
786
 /** HTTP socket interface operations */
555
 static struct interface_operation http_socket_operations[] = {
787
 static struct interface_operation http_socket_operations[] = {
788
+	INTF_OP ( xfer_window, struct http_request *, http_socket_window ),
556
 	INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
789
 	INTF_OP ( xfer_deliver, struct http_request *, http_socket_deliver ),
557
 	INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
790
 	INTF_OP ( xfer_window_changed, struct http_request *, http_step ),
558
-	INTF_OP ( intf_close, struct http_request *, http_done ),
791
+	INTF_OP ( intf_close, struct http_request *, http_close ),
559
 };
792
 };
560
 
793
 
561
 /** HTTP socket interface descriptor */
794
 /** HTTP socket interface descriptor */
563
 	INTF_DESC_PASSTHRU ( struct http_request, socket,
796
 	INTF_DESC_PASSTHRU ( struct http_request, socket,
564
 			     http_socket_operations, xfer );
797
 			     http_socket_operations, xfer );
565
 
798
 
799
+/** HTTP partial transfer interface operations */
800
+static struct interface_operation http_partial_operations[] = {
801
+	INTF_OP ( intf_close, struct http_request *, http_close ),
802
+};
803
+
804
+/** HTTP partial transfer interface descriptor */
805
+static struct interface_descriptor http_partial_desc =
806
+	INTF_DESC ( struct http_request, partial, http_partial_operations );
807
+
566
 /** HTTP data transfer interface operations */
808
 /** HTTP data transfer interface operations */
567
 static struct interface_operation http_xfer_operations[] = {
809
 static struct interface_operation http_xfer_operations[] = {
568
-	INTF_OP ( intf_close, struct http_request *, http_done ),
810
+	INTF_OP ( xfer_window, struct http_request *, http_xfer_window ),
811
+	INTF_OP ( block_read, struct http_request *, http_block_read ),
812
+	INTF_OP ( block_read_capacity, struct http_request *,
813
+		  http_block_read_capacity ),
814
+	INTF_OP ( intf_close, struct http_request *, http_close ),
815
+	INTF_OP ( acpi_describe, struct http_request *, http_acpi_describe ),
569
 };
816
 };
570
 
817
 
571
 /** HTTP data transfer interface descriptor */
818
 /** HTTP data transfer interface descriptor */
605
 		return -ENOMEM;
852
 		return -ENOMEM;
606
 	ref_init ( &http->refcnt, http_free );
853
 	ref_init ( &http->refcnt, http_free );
607
 	intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
854
 	intf_init ( &http->xfer, &http_xfer_desc, &http->refcnt );
855
+	intf_init ( &http->partial, &http_partial_desc, &http->refcnt );
608
        	http->uri = uri_get ( uri );
856
        	http->uri = uri_get ( uri );
609
 	intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
857
 	intf_init ( &http->socket, &http_socket_desc, &http->refcnt );
610
 	process_init ( &http->process, &http_process_desc, &http->refcnt );
858
 	process_init ( &http->process, &http_process_desc, &http->refcnt );
859
+	http->flags = HTTP_TX_PENDING;
611
 
860
 
612
 	/* Open socket */
861
 	/* Open socket */
613
 	memset ( &server, 0, sizeof ( server ) );
862
 	memset ( &server, 0, sizeof ( server ) );
630
  err:
879
  err:
631
 	DBGC ( http, "HTTP %p could not create request: %s\n", 
880
 	DBGC ( http, "HTTP %p could not create request: %s\n", 
632
 	       http, strerror ( rc ) );
881
 	       http, strerror ( rc ) );
633
-	http_done ( http, rc );
882
+	http_close ( http, rc );
634
 	ref_put ( &http->refcnt );
883
 	ref_put ( &http->refcnt );
635
 	return rc;
884
 	return rc;
636
 }
885
 }

Loading…
Cancel
Save