Browse Source

Update HTTP to use data-xfer interface.

tags/v0.9.3
Michael Brown 17 years ago
parent
commit
735e07268e
4 changed files with 269 additions and 285 deletions
  1. 13
    20
      src/core/linebuf.c
  2. 0
    46
      src/include/gpxe/http.h
  3. 2
    2
      src/include/gpxe/linebuf.h
  4. 254
    217
      src/net/tcp/http.c

+ 13
- 20
src/core/linebuf.c View File

57
  * @v linebuf			Line buffer
57
  * @v linebuf			Line buffer
58
  * @v data			New data to add
58
  * @v data			New data to add
59
  * @v len			Length of new data to add
59
  * @v len			Length of new data to add
60
- * @ret rc			Return status code
61
- * 
62
- * If line_buffer() returns >0, then an end of line has been reached
63
- * and the buffered-up line can be obtained from buffered_line().
64
- * Carriage returns and newlines will have been stripped, and the line
65
- * will be NUL-terminated.  This buffered line is valid only until the
66
- * next call to line_buffer() (or to empty_line_buffer()).
60
+ * @ret len			Consumed length, or negative error number
67
  *
61
  *
68
- * @c data and @c len will be updated to reflect the data consumed by
69
- * line_buffer().
62
+ * After calling line_buffer(), use buffered_line() to determine
63
+ * whether or not a complete line is available.  Carriage returns and
64
+ * newlines will have been stripped, and the line will be
65
+ * NUL-terminated.  This buffered line is valid only until the next
66
+ * call to line_buffer() (or to empty_line_buffer()).
70
  *
67
  *
71
  * Note that line buffers use dynamically allocated storage; you
68
  * Note that line buffers use dynamically allocated storage; you
72
  * should call empty_line_buffer() before freeing a @c struct @c
69
  * should call empty_line_buffer() before freeing a @c struct @c
73
  * line_buffer.
70
  * line_buffer.
74
  */
71
  */
75
-int line_buffer ( struct line_buffer *linebuf,
76
-		  const char **data, size_t *len ) {
72
+ssize_t line_buffer ( struct line_buffer *linebuf,
73
+		      const char *data, size_t len ) {
77
 	const char *eol;
74
 	const char *eol;
78
 	size_t consume;
75
 	size_t consume;
79
 	size_t new_len;
76
 	size_t new_len;
84
 		empty_line_buffer ( linebuf );
81
 		empty_line_buffer ( linebuf );
85
 
82
 
86
 	/* Search for line terminator */
83
 	/* Search for line terminator */
87
-	if ( ( eol = memchr ( *data, '\n', *len ) ) ) {
88
-		consume = ( eol - *data + 1 );
84
+	if ( ( eol = memchr ( data, '\n', len ) ) ) {
85
+		consume = ( eol - data + 1 );
89
 	} else {
86
 	} else {
90
-		consume = *len;
87
+		consume = len;
91
 	}
88
 	}
92
 
89
 
93
 	/* Reallocate data buffer and copy in new data */
90
 	/* Reallocate data buffer and copy in new data */
95
 	new_data = realloc ( linebuf->data, ( new_len + 1 ) );
92
 	new_data = realloc ( linebuf->data, ( new_len + 1 ) );
96
 	if ( ! new_data )
93
 	if ( ! new_data )
97
 		return -ENOMEM;
94
 		return -ENOMEM;
98
-	memcpy ( ( new_data + linebuf->len ), *data, consume );
95
+	memcpy ( ( new_data + linebuf->len ), data, consume );
99
 	new_data[new_len] = '\0';
96
 	new_data[new_len] = '\0';
100
 	linebuf->data = new_data;
97
 	linebuf->data = new_data;
101
 	linebuf->len = new_len;
98
 	linebuf->len = new_len;
102
 
99
 
103
-	/* Update data and len */
104
-	*data += consume;
105
-	*len -= consume;
106
-
107
 	/* If we have reached end of line, trim the line and mark as ready */
100
 	/* If we have reached end of line, trim the line and mark as ready */
108
 	if ( eol ) {
101
 	if ( eol ) {
109
 		linebuf->data[--linebuf->len] = '\0'; /* trim NL */
102
 		linebuf->data[--linebuf->len] = '\0'; /* trim NL */
112
 		linebuf->ready = 1;
105
 		linebuf->ready = 1;
113
 	}
106
 	}
114
 
107
 
115
-	return 0;
108
+	return consume;
116
 }
109
 }

+ 0
- 46
src/include/gpxe/http.h View File

7
  *
7
  *
8
  */
8
  */
9
 
9
 
10
-#include <stdint.h>
11
-#include <gpxe/stream.h>
12
-#include <gpxe/async.h>
13
-#include <gpxe/linebuf.h>
14
-#include <gpxe/uri.h>
15
-
16
 /** HTTP default port */
10
 /** HTTP default port */
17
 #define HTTP_PORT 80
11
 #define HTTP_PORT 80
18
 
12
 
19
 /** HTTPS default port */
13
 /** HTTPS default port */
20
 #define HTTPS_PORT 443
14
 #define HTTPS_PORT 443
21
 
15
 
22
-/** HTTP receive state */
23
-enum http_rx_state {
24
-	HTTP_RX_RESPONSE = 0,
25
-	HTTP_RX_HEADER,
26
-	HTTP_RX_DATA,
27
-	HTTP_RX_DEAD,
28
-};
29
-
30
-/**
31
- * An HTTP request
32
- *
33
- */
34
-struct http_request {
35
-	/** URI being fetched */
36
-	struct uri *uri;
37
-	/** Data buffer to fill */
38
-	struct buffer *buffer;
39
-	/** Asynchronous operation */
40
-	struct async async;
41
-
42
-	/** HTTP response code */
43
-	unsigned int response;
44
-	/** HTTP Content-Length */
45
-	size_t content_length;
46
-
47
-	/** Server address */
48
-	struct sockaddr server;
49
-	/** Stream application for this request */
50
-	struct stream_application stream;
51
-	/** Number of bytes already sent */
52
-	size_t tx_offset;
53
-	/** RX state */
54
-	enum http_rx_state rx_state;
55
-	/** Line buffer for received header lines */
56
-	struct line_buffer linebuf;
57
-};
58
-
59
-extern int http_get ( struct uri *uri, struct buffer *buffer,
60
-		      struct async *parent );
61
-
62
 #endif /* _GPXE_HTTP_H */
16
 #endif /* _GPXE_HTTP_H */

+ 2
- 2
src/include/gpxe/linebuf.h View File

21
 };
21
 };
22
 
22
 
23
 extern char * buffered_line ( struct line_buffer *linebuf );
23
 extern char * buffered_line ( struct line_buffer *linebuf );
24
-extern int line_buffer ( struct line_buffer *linebuf,
25
-			 const char **data, size_t *len );
24
+extern ssize_t line_buffer ( struct line_buffer *linebuf,
25
+			     const char *data, size_t len );
26
 extern void empty_line_buffer ( struct line_buffer *linebuf );
26
 extern void empty_line_buffer ( struct line_buffer *linebuf );
27
 
27
 
28
 #endif /* _GPXE_LINEBUF_H */
28
 #endif /* _GPXE_LINEBUF_H */

+ 254
- 217
src/net/tcp/http.c View File

23
  *
23
  *
24
  */
24
  */
25
 
25
 
26
-#include <stddef.h>
26
+#include <stdint.h>
27
 #include <stdlib.h>
27
 #include <stdlib.h>
28
 #include <stdio.h>
28
 #include <stdio.h>
29
 #include <string.h>
29
 #include <string.h>
31
 #include <byteswap.h>
31
 #include <byteswap.h>
32
 #include <errno.h>
32
 #include <errno.h>
33
 #include <assert.h>
33
 #include <assert.h>
34
-#include <gpxe/async.h>
35
 #include <gpxe/uri.h>
34
 #include <gpxe/uri.h>
36
-#include <gpxe/buffer.h>
37
-#include <gpxe/download.h>
38
-#include <gpxe/resolv.h>
39
-#include <gpxe/tcp.h>
35
+#include <gpxe/refcnt.h>
36
+#include <gpxe/iobuf.h>
37
+#include <gpxe/xfer.h>
38
+#include <gpxe/open.h>
39
+#include <gpxe/socket.h>
40
+#include <gpxe/tcpip.h>
41
+#include <gpxe/process.h>
42
+#include <gpxe/linebuf.h>
40
 #include <gpxe/tls.h>
43
 #include <gpxe/tls.h>
41
 #include <gpxe/http.h>
44
 #include <gpxe/http.h>
42
 
45
 
43
-static struct async_operations http_async_operations;
46
+/** HTTP receive state */
47
+enum http_rx_state {
48
+	HTTP_RX_RESPONSE = 0,
49
+	HTTP_RX_HEADER,
50
+	HTTP_RX_DATA,
51
+	HTTP_RX_DEAD,
52
+};
44
 
53
 
45
-static inline struct http_request *
46
-stream_to_http ( struct stream_application *app ) {
47
-	return container_of ( app, struct http_request, stream );
48
-}
54
+/**
55
+ * An HTTP request
56
+ *
57
+ */
58
+struct http_request {
59
+	/** Reference count */
60
+	struct refcnt refcnt;
61
+	/** Data transfer interface */
62
+	struct xfer_interface xfer;
63
+
64
+	/** URI being fetched */
65
+	struct uri *uri;
66
+	/** Transport layer interface */
67
+	struct xfer_interface socket;
68
+
69
+	/** TX process */
70
+	struct process process;
71
+
72
+	/** HTTP response code */
73
+	unsigned int response;
74
+	/** HTTP Content-Length */
75
+	size_t content_length;
76
+	/** Received length */
77
+	size_t rx_len;
78
+	/** RX state */
79
+	enum http_rx_state rx_state;
80
+	/** Line buffer for received header lines */
81
+	struct line_buffer linebuf;
82
+};
83
+
84
+/**
85
+ * Free HTTP request
86
+ *
87
+ * @v refcnt		Reference counter
88
+ */
89
+static void http_free ( struct refcnt *refcnt ) {
90
+	struct http_request *http =
91
+		container_of ( refcnt, struct http_request, refcnt );
92
+
93
+	uri_put ( http->uri );
94
+	empty_line_buffer ( &http->linebuf );
95
+	free ( http );
96
+};
49
 
97
 
50
 /**
98
 /**
51
  * Mark HTTP request as complete
99
  * Mark HTTP request as complete
52
  *
100
  *
53
  * @v http		HTTP request
101
  * @v http		HTTP request
54
  * @v rc		Return status code
102
  * @v rc		Return status code
55
- *
56
  */
103
  */
57
 static void http_done ( struct http_request *http, int rc ) {
104
 static void http_done ( struct http_request *http, int rc ) {
58
 
105
 
59
-	/* Close stream connection */
60
-	stream_close ( &http->stream );
61
-
62
 	/* Prevent further processing of any current packet */
106
 	/* Prevent further processing of any current packet */
63
 	http->rx_state = HTTP_RX_DEAD;
107
 	http->rx_state = HTTP_RX_DEAD;
64
 
108
 
65
-	/* Free up any dynamically allocated storage */
66
-	empty_line_buffer ( &http->linebuf );
67
-
68
 	/* If we had a Content-Length, and the received content length
109
 	/* If we had a Content-Length, and the received content length
69
 	 * isn't correct, flag an error
110
 	 * isn't correct, flag an error
70
 	 */
111
 	 */
71
 	if ( http->content_length &&
112
 	if ( http->content_length &&
72
-	     ( http->content_length != http->buffer->fill ) ) {
113
+	     ( http->content_length != http->rx_len ) ) {
73
 		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
114
 		DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
74
-		       http, http->buffer->fill, http->content_length );
115
+		       http, http->rx_len, http->content_length );
75
 		rc = -EIO;
116
 		rc = -EIO;
76
 	}
117
 	}
77
 
118
 
78
-	/* Mark async operation as complete */
79
-	async_done ( &http->async, rc );
119
+	/* Remove process */
120
+	process_del ( &http->process );
121
+
122
+	/* Close all data transfer interfaces */
123
+	xfer_nullify ( &http->socket );
124
+	xfer_close ( &http->socket, rc );
125
+	xfer_nullify ( &http->xfer );
126
+	xfer_close ( &http->xfer, rc );
80
 }
127
 }
81
 
128
 
82
 /**
129
 /**
103
  *
150
  *
104
  * @v http		HTTP request
151
  * @v http		HTTP request
105
  * @v response		HTTP response
152
  * @v response		HTTP response
153
+ * @ret rc		Return status code
106
  */
154
  */
107
-static void http_rx_response ( struct http_request *http, char *response ) {
155
+static int http_rx_response ( struct http_request *http, char *response ) {
108
 	char *spc;
156
 	char *spc;
109
-	int rc = -EIO;
157
+	int rc;
110
 
158
 
111
 	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
159
 	DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
112
 
160
 
113
 	/* Check response starts with "HTTP/" */
161
 	/* Check response starts with "HTTP/" */
114
 	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
162
 	if ( strncmp ( response, "HTTP/", 5 ) != 0 )
115
-		goto err;
163
+		return -EIO;
116
 
164
 
117
 	/* Locate and check response code */
165
 	/* Locate and check response code */
118
 	spc = strchr ( response, ' ' );
166
 	spc = strchr ( response, ' ' );
119
 	if ( ! spc )
167
 	if ( ! spc )
120
-		goto err;
168
+		return -EIO;
121
 	http->response = strtoul ( spc, NULL, 10 );
169
 	http->response = strtoul ( spc, NULL, 10 );
122
 	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
170
 	if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
123
-		goto err;
171
+		return rc;
124
 
172
 
125
 	/* Move to received headers */
173
 	/* Move to received headers */
126
 	http->rx_state = HTTP_RX_HEADER;
174
 	http->rx_state = HTTP_RX_HEADER;
127
-	return;
128
-
129
- err:
130
-	DBGC ( http, "HTTP %p bad response\n", http );
131
-	http_done ( http, rc );
132
-	return;
175
+	return 0;
133
 }
176
 }
134
 
177
 
135
 /**
178
 /**
142
 static int http_rx_content_length ( struct http_request *http,
185
 static int http_rx_content_length ( struct http_request *http,
143
 				    const char *value ) {
186
 				    const char *value ) {
144
 	char *endp;
187
 	char *endp;
145
-	int rc;
146
 
188
 
147
 	http->content_length = strtoul ( value, &endp, 10 );
189
 	http->content_length = strtoul ( value, &endp, 10 );
148
 	if ( *endp != '\0' ) {
190
 	if ( *endp != '\0' ) {
151
 		return -EIO;
193
 		return -EIO;
152
 	}
194
 	}
153
 
195
 
154
-	/* Try to presize the receive buffer */
155
-	if ( ( rc = expand_buffer ( http->buffer,
156
-				    http->content_length ) ) != 0 ) {
157
-		/* May as well abandon the download now; it will fail */
158
-		DBGC ( http, "HTTP %p could not presize buffer: %s\n",
159
-		       http, strerror ( rc ) );
160
-		return rc;
161
-	}
196
+	/* Use seek() to notify recipient of filesize */
197
+	xfer_seek ( &http->xfer, http->content_length, SEEK_SET );
198
+	xfer_seek ( &http->xfer, 0, SEEK_SET );
162
 
199
 
163
 	return 0;
200
 	return 0;
164
 }
201
 }
165
 
202
 
166
-/**
167
- * An HTTP header handler
168
- *
169
- */
203
+/** An HTTP header handler */
170
 struct http_header_handler {
204
 struct http_header_handler {
171
 	/** Name (e.g. "Content-Length") */
205
 	/** Name (e.g. "Content-Length") */
172
 	const char *header;
206
 	const char *header;
195
  *
229
  *
196
  * @v http		HTTP request
230
  * @v http		HTTP request
197
  * @v header		HTTP header
231
  * @v header		HTTP header
232
+ * @ret rc		Return status code
198
  */
233
  */
199
-static void http_rx_header ( struct http_request *http, char *header ) {
234
+static int http_rx_header ( struct http_request *http, char *header ) {
200
 	struct http_header_handler *handler;
235
 	struct http_header_handler *handler;
201
 	char *separator;
236
 	char *separator;
202
 	char *value;
237
 	char *value;
203
-	int rc = -EIO;
238
+	int rc;
204
 
239
 
205
 	/* An empty header line marks the transition to the data phase */
240
 	/* An empty header line marks the transition to the data phase */
206
 	if ( ! header[0] ) {
241
 	if ( ! header[0] ) {
207
 		DBGC ( http, "HTTP %p start of data\n", http );
242
 		DBGC ( http, "HTTP %p start of data\n", http );
208
 		empty_line_buffer ( &http->linebuf );
243
 		empty_line_buffer ( &http->linebuf );
209
 		http->rx_state = HTTP_RX_DATA;
244
 		http->rx_state = HTTP_RX_DATA;
210
-		return;
245
+		return 0;
211
 	}
246
 	}
212
 
247
 
213
 	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
248
 	DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
214
 
249
 
215
 	/* Split header at the ": " */
250
 	/* Split header at the ": " */
216
 	separator = strstr ( header, ": " );
251
 	separator = strstr ( header, ": " );
217
-	if ( ! separator )
218
-		goto err;
252
+	if ( ! separator ) {
253
+		DBGC ( http, "HTTP %p malformed header\n", http );
254
+		return -EIO;
255
+	}
219
 	*separator = '\0';
256
 	*separator = '\0';
220
 	value = ( separator + 2 );
257
 	value = ( separator + 2 );
221
 
258
 
223
 	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
260
 	for ( handler = http_header_handlers ; handler->header ; handler++ ) {
224
 		if ( strcasecmp ( header, handler->header ) == 0 ) {
261
 		if ( strcasecmp ( header, handler->header ) == 0 ) {
225
 			if ( ( rc = handler->rx ( http, value ) ) != 0 )
262
 			if ( ( rc = handler->rx ( http, value ) ) != 0 )
226
-				goto err;
263
+				return rc;
227
 			break;
264
 			break;
228
 		}
265
 		}
229
 	}
266
 	}
230
-	return;
231
-
232
- err:
233
-	DBGC ( http, "HTTP %p bad header\n", http );
234
-	http_done ( http, rc );
235
-	return;
267
+	return 0;
236
 }
268
 }
237
 
269
 
270
+/** An HTTP line-based data handler */
271
+struct http_line_handler {
272
+	/** Handle line
273
+	 *
274
+	 * @v http	HTTP request
275
+	 * @v line	Line to handle
276
+	 * @ret rc	Return status code
277
+	 */
278
+	int ( * rx ) ( struct http_request *http, char *line );
279
+};
280
+
281
+/** List of HTTP line-based data handlers */
282
+struct http_line_handler http_line_handlers[] = {
283
+	[HTTP_RX_RESPONSE]	= { .rx = http_rx_response },
284
+	[HTTP_RX_HEADER]	= { .rx = http_rx_header },
285
+};
286
+
238
 /**
287
 /**
239
  * Handle new data arriving via HTTP connection in the data phase
288
  * Handle new data arriving via HTTP connection in the data phase
240
  *
289
  *
241
  * @v http		HTTP request
290
  * @v http		HTTP request
242
- * @v data		New data
243
- * @v len		Length of new data
291
+ * @v iobuf		I/O buffer
292
+ * @ret rc		Return status code
244
  */
293
  */
245
-static void http_rx_data ( struct http_request *http,
246
-			   const char *data, size_t len ) {
294
+static int http_rx_data ( struct http_request *http,
295
+			  struct io_buffer *iobuf ) {
247
 	int rc;
296
 	int rc;
248
 
297
 
249
-	/* Fill data buffer */
250
-	if ( ( rc = fill_buffer ( http->buffer, data,
251
-				  http->buffer->fill, len ) ) != 0 ) {
252
-		DBGC ( http, "HTTP %p failed to fill data buffer: %s\n",
253
-		       http, strerror ( rc ) );
254
-		http_done ( http, rc );
255
-		return;
256
-	}
298
+	/* Update received length */
299
+	http->rx_len += iob_len ( iobuf );
257
 
300
 
258
-	/* Update progress */
259
-	http->async.completed = http->buffer->fill;
260
-	http->async.total = http->content_length;
301
+	/* Hand off data buffer */
302
+	if ( ( rc = xfer_deliver_iob ( &http->xfer, iobuf ) ) != 0 )
303
+		return rc;
261
 
304
 
262
 	/* If we have reached the content-length, stop now */
305
 	/* If we have reached the content-length, stop now */
263
 	if ( http->content_length &&
306
 	if ( http->content_length &&
264
-	     ( http->buffer->fill >= http->content_length ) ) {
307
+	     ( http->rx_len >= http->content_length ) ) {
265
 		http_done ( http, 0 );
308
 		http_done ( http, 0 );
266
 	}
309
 	}
310
+
311
+	return 0;
267
 }
312
 }
268
 
313
 
269
 /**
314
 /**
270
  * Handle new data arriving via HTTP connection
315
  * Handle new data arriving via HTTP connection
271
  *
316
  *
272
- * @v http		HTTP request
273
- * @v data		New data
274
- * @v len		Length of new data
317
+ * @v socket		Transport layer interface
318
+ * @v iobuf		I/O buffer
319
+ * @ret rc		Return status code
275
  */
320
  */
276
-static void http_newdata ( struct stream_application *app,
277
-			   void *data, size_t len ) {
278
-	struct http_request *http = stream_to_http ( app );
279
-	const char *buf = data;
321
+static int http_socket_deliver_iob ( struct xfer_interface *socket,
322
+				     struct io_buffer *iobuf ) {
323
+	struct http_request *http =
324
+		container_of ( socket, struct http_request, socket );
325
+	struct http_line_handler *lh;
280
 	char *line;
326
 	char *line;
281
-	int rc;
327
+	ssize_t len;
328
+	int rc = 0;
282
 
329
 
283
-	while ( len ) {
284
-		if ( http->rx_state == HTTP_RX_DEAD ) {
330
+	while ( iob_len ( iobuf ) ) {
331
+		switch ( http->rx_state ) {
332
+		case HTTP_RX_DEAD:
285
 			/* Do no further processing */
333
 			/* Do no further processing */
286
-			return;
287
-		} else if ( http->rx_state == HTTP_RX_DATA ) {
334
+			goto done;
335
+		case HTTP_RX_DATA:
288
 			/* Once we're into the data phase, just fill
336
 			/* Once we're into the data phase, just fill
289
 			 * the data buffer
337
 			 * the data buffer
290
 			 */
338
 			 */
291
-			http_rx_data ( http, buf, len );
292
-			return;
293
-		} else {
339
+			rc = http_rx_data ( http, iobuf );
340
+			iobuf = NULL;
341
+			goto done;
342
+		case HTTP_RX_RESPONSE:
343
+		case HTTP_RX_HEADER:
294
 			/* In the other phases, buffer and process a
344
 			/* In the other phases, buffer and process a
295
 			 * line at a time
345
 			 * line at a time
296
 			 */
346
 			 */
297
-			if ( ( rc = line_buffer ( &http->linebuf, &buf,
298
-						  &len ) ) != 0 ) {
347
+			len = line_buffer ( &http->linebuf, iobuf->data,
348
+					    iob_len ( iobuf ) );
349
+			if ( len < 0 ) {
299
 				DBGC ( http, "HTTP %p could not buffer line: "
350
 				DBGC ( http, "HTTP %p could not buffer line: "
300
 				       "%s\n", http, strerror ( rc ) );
351
 				       "%s\n", http, strerror ( rc ) );
301
-				http_done ( http, rc );
302
-				return;
352
+				goto done;
303
 			}
353
 			}
304
-			if ( ( line = buffered_line ( &http->linebuf ) ) ) {
305
-				switch ( http->rx_state ) {
306
-				case HTTP_RX_RESPONSE:
307
-					http_rx_response ( http, line );
308
-					break;
309
-				case HTTP_RX_HEADER:
310
-					http_rx_header ( http, line );
311
-					break;
312
-				default:
313
-					assert ( 0 );
314
-					break;
315
-				}
354
+			iob_pull ( iobuf, len );
355
+			line = buffered_line ( &http->linebuf );
356
+			if ( line ) {
357
+				lh = &http_line_handlers[http->rx_state];
358
+				if ( ( rc = lh->rx ( http, line ) ) != 0 )
359
+					goto done;
316
 			}
360
 			}
361
+			break;
362
+		default:
363
+			assert ( 0 );
364
+			break;
317
 		}
365
 		}
318
 	}
366
 	}
367
+
368
+ done:
369
+	if ( rc )
370
+		http_done ( http, rc );
371
+	free_iob ( iobuf );
372
+	return rc;
319
 }
373
 }
320
 
374
 
321
 /**
375
 /**
322
- * Send HTTP data
376
+ * HTTP process
323
  *
377
  *
324
- * @v app		Stream application
325
- * @v buf		Temporary data buffer
326
- * @v len		Length of temporary data buffer
378
+ * @v process		Process
327
  */
379
  */
328
-static void http_senddata ( struct stream_application *app,
329
-			    void *buf, size_t len ) {
330
-	struct http_request *http = stream_to_http ( app );
380
+static void http_step ( struct process *process ) {
381
+	struct http_request *http =
382
+		container_of ( process, struct http_request, process );
331
 	const char *path = http->uri->path;
383
 	const char *path = http->uri->path;
332
 	const char *host = http->uri->host;
384
 	const char *host = http->uri->host;
333
 	const char *query = http->uri->query;
385
 	const char *query = http->uri->query;
386
+	int rc;
334
 
387
 
335
-	len = snprintf ( buf, len,
336
-			 "GET %s%s%s HTTP/1.1\r\n"
337
-			 "User-Agent: gPXE/" VERSION "\r\n"
338
-			 "Host: %s\r\n"
339
-			 "\r\n",
340
-			 ( path ? path : "/" ),
341
-			 ( query ? "?" : "" ),
342
-			 ( query ? query : "" ),
343
-			 host );
344
-
345
-	stream_send ( app, ( buf + http->tx_offset ),
346
-		      ( len - http->tx_offset ) );
388
+	if ( xfer_ready ( &http->socket ) == 0 ) {
389
+		process_del ( &http->process );
390
+		if ( ( rc = xfer_printf ( &http->socket,
391
+					  "GET %s%s%s HTTP/1.1\r\n"
392
+					  "User-Agent: gPXE/" VERSION "\r\n"
393
+					  "Host: %s\r\n"
394
+					  "\r\n",
395
+					  ( path ? path : "/" ),
396
+					  ( query ? "?" : "" ),
397
+					  ( query ? query : "" ),
398
+					  host ) ) != 0 ) {
399
+			http_done ( http, rc );
400
+		}
401
+	}
347
 }
402
 }
348
 
403
 
349
 /**
404
 /**
350
- * HTTP data acknowledged
405
+ * HTTP connection closed by network stack
351
  *
406
  *
352
- * @v app		Stream application
353
- * @v len		Length of acknowledged data
407
+ * @v socket		Transport layer interface
408
+ * @v rc		Reason for close
354
  */
409
  */
355
-static void http_acked ( struct stream_application *app, size_t len ) {
356
-	struct http_request *http = stream_to_http ( app );
410
+static void http_socket_close ( struct xfer_interface *socket, int rc ) {
411
+	struct http_request *http =
412
+		container_of ( socket, struct http_request, socket );
357
 
413
 
358
-	http->tx_offset += len;
414
+	DBGC ( http, "HTTP %p socket closed: %s\n",
415
+	       http, strerror ( rc ) );
416
+	
417
+	http_done ( http, rc );
359
 }
418
 }
360
 
419
 
420
+/** HTTP socket operations */
421
+static struct xfer_interface_operations http_socket_operations = {
422
+	.close		= http_socket_close,
423
+	.vredirect	= xfer_vopen,
424
+	.request	= ignore_xfer_request,
425
+	.seek		= ignore_xfer_seek,
426
+	.alloc_iob	= default_xfer_alloc_iob,
427
+	.deliver_iob	= http_socket_deliver_iob,
428
+	.deliver_raw	= xfer_deliver_as_iob,
429
+};
430
+
361
 /**
431
 /**
362
- * HTTP connection closed by network stack
432
+ * Close HTTP data transfer interface
363
  *
433
  *
364
- * @v app		Stream application
434
+ * @v xfer		Data transfer interface
435
+ * @v rc		Reason for close
365
  */
436
  */
366
-static void http_closed ( struct stream_application *app, int rc ) {
367
-	struct http_request *http = stream_to_http ( app );
437
+static void http_xfer_close ( struct xfer_interface *xfer, int rc ) {
438
+	struct http_request *http =
439
+		container_of ( xfer, struct http_request, xfer );
368
 
440
 
369
-	DBGC ( http, "HTTP %p connection closed: %s\n",
441
+	DBGC ( http, "HTTP %p interface closed: %s\n",
370
 	       http, strerror ( rc ) );
442
 	       http, strerror ( rc ) );
371
-	
443
+
372
 	http_done ( http, rc );
444
 	http_done ( http, rc );
373
 }
445
 }
374
 
446
 
375
-/** HTTP stream operations */
376
-static struct stream_application_operations http_stream_operations = {
377
-	.closed		= http_closed,
378
-	.acked		= http_acked,
379
-	.newdata	= http_newdata,
380
-	.senddata	= http_senddata,
447
+/** HTTP data transfer interface operations */
448
+static struct xfer_interface_operations http_xfer_operations = {
449
+	.close		= http_xfer_close,
450
+	.vredirect	= ignore_xfer_vredirect,
451
+	.request	= ignore_xfer_request,
452
+	.seek		= ignore_xfer_seek,
453
+	.alloc_iob	= default_xfer_alloc_iob,
454
+	.deliver_iob	= xfer_deliver_as_raw,
455
+	.deliver_raw	= ignore_xfer_deliver_raw,
381
 };
456
 };
382
 
457
 
383
 /**
458
 /**
384
- * Initiate a HTTP connection
459
+ * Initiate an HTTP connection
385
  *
460
  *
461
+ * @v xfer		Data transfer interface
386
  * @v uri		Uniform Resource Identifier
462
  * @v uri		Uniform Resource Identifier
387
- * @v buffer		Buffer into which to download file
388
- * @v parent		Parent asynchronous operation
389
  * @ret rc		Return status code
463
  * @ret rc		Return status code
390
  */
464
  */
391
-int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
392
-	struct http_request *http = NULL;
393
-	struct sockaddr_tcpip *st;
465
+int http_open ( struct xfer_interface *xfer, struct uri *uri ) {
466
+	struct http_request *http;
467
+	struct sockaddr_tcpip server;
394
 	int rc;
468
 	int rc;
395
 
469
 
470
+	/* Sanity checks */
471
+	if ( ! uri->host )
472
+		return -EINVAL;
473
+
396
 	/* Allocate and populate HTTP structure */
474
 	/* Allocate and populate HTTP structure */
397
 	http = malloc ( sizeof ( *http ) );
475
 	http = malloc ( sizeof ( *http ) );
398
 	if ( ! http )
476
 	if ( ! http )
399
 		return -ENOMEM;
477
 		return -ENOMEM;
400
 	memset ( http, 0, sizeof ( *http ) );
478
 	memset ( http, 0, sizeof ( *http ) );
401
-	http->uri = uri;
402
-	http->buffer = buffer;
403
-	async_init ( &http->async, &http_async_operations, parent );
404
-	http->stream.op = &http_stream_operations;
405
-	st = ( struct sockaddr_tcpip * ) &http->server;
406
-	st->st_port = htons ( uri_port ( http->uri, HTTP_PORT ) );
407
-
408
-	/* Open TCP connection */
409
-	if ( ( rc = tcp_open ( &http->stream ) ) != 0 )
479
+	http->refcnt.free = http_free;
480
+	xfer_init ( &http->xfer, &http_xfer_operations, &http->refcnt );
481
+       	http->uri = uri_get ( uri );
482
+	xfer_init ( &http->socket, &http_socket_operations, &http->refcnt );
483
+	process_init ( &http->process, http_step, &http->refcnt );
484
+
485
+	/* Open socket */
486
+	memset ( &server, 0, sizeof ( server ) );
487
+	server.st_port = htons ( uri_port ( http->uri, HTTP_PORT ) );
488
+	if ( ( rc = xfer_open_named_socket ( &http->socket, SOCK_STREAM,
489
+					     ( struct sockaddr * ) &server,
490
+					     uri->host, NULL ) ) != 0 )
410
 		goto err;
491
 		goto err;
492
+
493
+#if 0
411
 	if ( strcmp ( http->uri->scheme, "https" ) == 0 ) {
494
 	if ( strcmp ( http->uri->scheme, "https" ) == 0 ) {
412
 		st->st_port = htons ( uri_port ( http->uri, HTTPS_PORT ) );
495
 		st->st_port = htons ( uri_port ( http->uri, HTTPS_PORT ) );
413
 		if ( ( rc = add_tls ( &http->stream ) ) != 0 )
496
 		if ( ( rc = add_tls ( &http->stream ) ) != 0 )
414
 			goto err;
497
 			goto err;
415
 	}
498
 	}
499
+#endif
416
 
500
 
417
-	/* Start name resolution.  The download proper will start when
418
-	 * name resolution completes.
419
-	 */
420
-	if ( ( rc = resolv ( uri->host, &http->server, &http->async ) ) != 0 )
421
-		goto err;
422
-
501
+	/* Attach to parent interface, mortalise self, and return */
502
+	xfer_plug_plug ( &http->xfer, xfer );
503
+	ref_put ( &http->refcnt );
423
 	return 0;
504
 	return 0;
424
 
505
 
425
  err:
506
  err:
426
 	DBGC ( http, "HTTP %p could not create request: %s\n", 
507
 	DBGC ( http, "HTTP %p could not create request: %s\n", 
427
 	       http, strerror ( rc ) );
508
 	       http, strerror ( rc ) );
428
-	async_uninit ( &http->async );
429
-	free ( http );
509
+	http_done ( http, rc );
510
+	ref_put ( &http->refcnt );
430
 	return rc;
511
 	return rc;
431
 }
512
 }
432
 
513
 
433
-/**
434
- * Handle name resolution completion
435
- *
436
- * @v async		HTTP asynchronous operation
437
- * @v signal		SIGCHLD
438
- */
439
-static void http_sigchld ( struct async *async, enum signal signal __unused ) {
440
-	struct http_request *http =
441
-		container_of ( async, struct http_request, async );
442
-	int rc;
443
-
444
-	/* If name resolution failed, abort now */
445
-	async_wait ( async, &rc, 1 );
446
-	if ( rc != 0 ) {
447
-		http_done ( http, rc );
448
-		return;
449
-	}
450
-
451
-	/* Otherwise, start the HTTP connection */
452
-	if ( ( rc = stream_connect ( &http->stream, &http->server ) ) != 0 ) {
453
-		DBGC ( http, "HTTP %p could not connect stream: %s\n",
454
-		       http, strerror ( rc ) );
455
-		http_done ( http, rc );
456
-		return;
457
-	}
458
-}
459
-
460
-/**
461
- * Free HTTP connection
462
- *
463
- * @v async		Asynchronous operation
464
- */
465
-static void http_reap ( struct async *async ) {
466
-	free ( container_of ( async, struct http_request, async ) );
467
-}
468
-
469
-/** HTTP asynchronous operations */
470
-static struct async_operations http_async_operations = {
471
-	.reap = http_reap,
472
-	.signal = {
473
-		[SIGCHLD] = http_sigchld,
474
-	},
475
-};
476
-
477
-/** HTTP download protocol */
478
-struct download_protocol http_download_protocol __download_protocol = {
479
-	.name = "http",
480
-	.start_download = http_get,
514
+/** HTTP URI opener */
515
+struct uri_opener http_uri_opener __uri_opener = {
516
+	.scheme	= "http",
517
+	.open	= http_open,
481
 };
518
 };
482
 
519
 
483
-/** HTTPS download protocol */
484
-struct download_protocol https_download_protocol __download_protocol = {
485
-	.name = "https",
486
-	.start_download = http_get,
520
+/** HTTPS URI opener */
521
+struct uri_opener https_uri_opener __uri_opener = {
522
+	.scheme	= "https",
523
+	.open	= http_open,
487
 };
524
 };

Loading…
Cancel
Save