HTTP/DNS now working fully asynchronously. HTTP/IP addresses and any
[people/sha0/gpxe.git] / src / net / tcp / http.c
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /**
20  * @file
21  *
22  * Hyper Text Transfer Protocol (HTTP)
23  *
24  */
25
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <byteswap.h>
31 #include <errno.h>
32 #include <assert.h>
33 #include <vsprintf.h>
34 #include <gpxe/async.h>
35 #include <gpxe/uri.h>
36 #include <gpxe/buffer.h>
37 #include <gpxe/download.h>
38 #include <gpxe/http.h>
39
40 static inline struct http_request *
41 tcp_to_http ( struct tcp_application *app ) {
42         return container_of ( app, struct http_request, tcp );
43 }
44
45 /**
46  * Mark HTTP request as complete
47  *
48  * @v http              HTTP request
49  * @v rc                Return status code
50  *
51  */
52 static void http_done ( struct http_request *http, int rc ) {
53
54         /* Close TCP connection */
55         tcp_close ( &http->tcp );
56
57         /* Prevent further processing of any current packet */
58         http->rx_state = HTTP_RX_DEAD;
59
60         /* Free up any dynamically allocated storage */
61         empty_line_buffer ( &http->linebuf );
62
63         /* If we had a Content-Length, and the received content length
64          * isn't correct, flag an error
65          */
66         if ( http->content_length &&
67              ( http->content_length != http->buffer->fill ) ) {
68                 DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
69                        http, http->buffer->fill, http->content_length );
70                 rc = -EIO;
71         }
72
73         /* Mark async operation as complete */
74         async_done ( &http->async, rc );
75 }
76
77 /**
78  * Convert HTTP response code to return status code
79  *
80  * @v response          HTTP response code
81  * @ret rc              Return status code
82  */
83 static int http_response_to_rc ( unsigned int response ) {
84         switch ( response ) {
85         case 200:
86                 return 0;
87         case 404:
88                 return -ENOENT;
89         case 403:
90                 return -EPERM;
91         default:
92                 return -EIO;
93         }
94 }
95
96 /**
97  * Handle HTTP response
98  *
99  * @v http              HTTP request
100  * @v response          HTTP response
101  */
102 static void http_rx_response ( struct http_request *http, char *response ) {
103         char *spc;
104         int rc = -EIO;
105
106         DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
107
108         /* Check response starts with "HTTP/" */
109         if ( strncmp ( response, "HTTP/", 5 ) != 0 )
110                 goto err;
111
112         /* Locate and check response code */
113         spc = strchr ( response, ' ' );
114         if ( ! spc )
115                 goto err;
116         http->response = strtoul ( spc, NULL, 10 );
117         if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
118                 goto err;
119
120         /* Move to received headers */
121         http->rx_state = HTTP_RX_HEADER;
122         return;
123
124  err:
125         DBGC ( http, "HTTP %p bad response\n", http );
126         http_done ( http, rc );
127         return;
128 }
129
130 /**
131  * Handle HTTP Content-Length header
132  *
133  * @v http              HTTP request
134  * @v value             HTTP header value
135  * @ret rc              Return status code
136  */
137 static int http_rx_content_length ( struct http_request *http,
138                                     const char *value ) {
139         char *endp;
140
141         http->content_length = strtoul ( value, &endp, 10 );
142         if ( *endp != '\0' ) {
143                 DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
144                        http, value );
145                 return -EIO;
146         }
147
148         return 0;
149 }
150
151 /**
152  * An HTTP header handler
153  *
154  */
155 struct http_header_handler {
156         /** Name (e.g. "Content-Length") */
157         const char *header;
158         /** Handle received header
159          *
160          * @v http      HTTP request
161          * @v value     HTTP header value
162          * @ret rc      Return status code
163          */
164         int ( * rx ) ( struct http_request *http, const char *value );
165 };
166
167 /** List of HTTP header handlers */
168 struct http_header_handler http_header_handlers[] = {
169         {
170                 .header = "Content-Length",
171                 .rx = http_rx_content_length,
172         },
173         { NULL, NULL }
174 };
175
176 /**
177  * Handle HTTP header
178  *
179  * @v http              HTTP request
180  * @v header            HTTP header
181  */
182 static void http_rx_header ( struct http_request *http, char *header ) {
183         struct http_header_handler *handler;
184         char *separator;
185         char *value;
186         int rc = -EIO;
187
188         /* An empty header line marks the transition to the data phase */
189         if ( ! header[0] ) {
190                 DBGC ( http, "HTTP %p start of data\n", http );
191                 empty_line_buffer ( &http->linebuf );
192                 http->rx_state = HTTP_RX_DATA;
193                 return;
194         }
195
196         DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
197
198         /* Split header at the ": " */
199         separator = strstr ( header, ": " );
200         if ( ! separator )
201                 goto err;
202         *separator = '\0';
203         value = ( separator + 2 );
204
205         /* Hand off to header handler, if one exists */
206         for ( handler = http_header_handlers ; handler->header ; handler++ ) {
207                 if ( strcasecmp ( header, handler->header ) == 0 ) {
208                         if ( ( rc = handler->rx ( http, value ) ) != 0 )
209                                 goto err;
210                         break;
211                 }
212         }
213         return;
214
215  err:
216         DBGC ( http, "HTTP %p bad header\n", http );
217         http_done ( http, rc );
218         return;
219 }
220
221 /**
222  * Handle new data arriving via HTTP connection in the data phase
223  *
224  * @v http              HTTP request
225  * @v data              New data
226  * @v len               Length of new data
227  */
228 static void http_rx_data ( struct http_request *http,
229                            const char *data, size_t len ) {
230         int rc;
231
232         /* Fill data buffer */
233         if ( ( rc = fill_buffer ( http->buffer, data,
234                                   http->buffer->fill, len ) ) != 0 ) {
235                 DBGC ( http, "HTTP %p failed to fill data buffer: %s\n",
236                        http, strerror ( rc ) );
237                 http_done ( http, rc );
238                 return;
239         }
240
241         /* If we have reached the content-length, stop now */
242         if ( http->content_length &&
243              ( http->buffer->fill >= http->content_length ) ) {
244                 http_done ( http, 0 );
245         }
246 }
247
248 /**
249  * Handle new data arriving via HTTP connection
250  *
251  * @v http              HTTP request
252  * @v data              New data
253  * @v len               Length of new data
254  */
255 static void http_newdata ( struct tcp_application *app,
256                            void *data, size_t len ) {
257         struct http_request *http = tcp_to_http ( app );
258         const char *buf = data;
259         char *line;
260         int rc;
261
262         while ( len ) {
263                 if ( http->rx_state == HTTP_RX_DEAD ) {
264                         /* Do no further processing */
265                         return;
266                 } else if ( http->rx_state == HTTP_RX_DATA ) {
267                         /* Once we're into the data phase, just fill
268                          * the data buffer
269                          */
270                         http_rx_data ( http, buf, len );
271                         return;
272                 } else {
273                         /* In the other phases, buffer and process a
274                          * line at a time
275                          */
276                         if ( ( rc = line_buffer ( &http->linebuf, &buf,
277                                                   &len ) ) != 0 ) {
278                                 DBGC ( http, "HTTP %p could not buffer line: "
279                                        "%s\n", http, strerror ( rc ) );
280                                 http_done ( http, rc );
281                                 return;
282                         }
283                         if ( ( line = buffered_line ( &http->linebuf ) ) ) {
284                                 switch ( http->rx_state ) {
285                                 case HTTP_RX_RESPONSE:
286                                         http_rx_response ( http, line );
287                                         break;
288                                 case HTTP_RX_HEADER:
289                                         http_rx_header ( http, line );
290                                         break;
291                                 default:
292                                         assert ( 0 );
293                                         break;
294                                 }
295                         }
296                 }
297         }
298 }
299
300 /**
301  * Send HTTP data
302  *
303  * @v app               TCP application
304  * @v buf               Temporary data buffer
305  * @v len               Length of temporary data buffer
306  */
307 static void http_senddata ( struct tcp_application *app,
308                             void *buf, size_t len ) {
309         struct http_request *http = tcp_to_http ( app );
310         const char *path = http->uri->path;
311         const char *host = http->uri->host;
312
313         if ( ! path )
314                 path = "/";
315
316         len = snprintf ( buf, len,
317                          "GET %s HTTP/1.1\r\n"
318                          "User-Agent: gPXE/" VERSION "\r\n"
319                          "Host: %s\r\n"
320                          "\r\n", path, host );
321
322         tcp_send ( app, ( buf + http->tx_offset ), ( len - http->tx_offset ) );
323 }
324
325 /**
326  * HTTP data acknowledged
327  *
328  * @v app               TCP application
329  * @v len               Length of acknowledged data
330  */
331 static void http_acked ( struct tcp_application *app, size_t len ) {
332         struct http_request *http = tcp_to_http ( app );
333
334         http->tx_offset += len;
335 }
336
337 /**
338  * HTTP connection closed by network stack
339  *
340  * @v app               TCP application
341  */
342 static void http_closed ( struct tcp_application *app, int rc ) {
343         struct http_request *http = tcp_to_http ( app );
344
345         DBGC ( http, "HTTP %p connection closed: %s\n",
346                http, strerror ( rc ) );
347         
348         http_done ( http, rc );
349 }
350
351 /** HTTP TCP operations */
352 static struct tcp_operations http_tcp_operations = {
353         .closed         = http_closed,
354         .acked          = http_acked,
355         .newdata        = http_newdata,
356         .senddata       = http_senddata,
357 };
358
359 /**
360  * Reap asynchronous operation
361  *
362  * @v async             Asynchronous operation
363  */
364 static void http_reap ( struct async *async ) {
365         struct http_request *http =
366                 container_of ( async, struct http_request, async );
367
368         free ( http );
369 }
370
371 /**
372  * Handle name resolution completion
373  *
374  * @v async             HTTP asynchronous operation
375  * @v signal            SIGCHLD
376  */
377 static void http_sigchld ( struct async *async, enum signal signal __unused ) {
378         struct http_request *http =
379                 container_of ( async, struct http_request, async );
380         struct sockaddr_tcpip *st = ( struct sockaddr_tcpip * ) &http->server;
381         int rc;
382
383         /* Reap child */
384         async_wait ( async, &rc, 1 );
385
386         /* If name resolution failed, abort now */
387         if ( rc != 0 ) {
388                 http_done ( http, rc );
389                 return;
390         }
391
392         /* Otherwise, start the HTTP connection */
393         http->tcp.tcp_op = &http_tcp_operations;
394         st->st_port = htons ( uri_port ( http->uri, HTTP_PORT ) );
395         if ( ( rc = tcp_connect ( &http->tcp, st, 0 ) ) != 0 ) {
396                 DBGC ( http, "HTTP %p could not open TCP connection: %s\n",
397                        http, strerror ( rc ) );
398                 http_done ( http, rc );
399                 return;
400         }
401 }
402
403 /** HTTP asynchronous operations */
404 static struct async_operations http_async_operations = {
405         .reap = http_reap,
406         .signal = {
407                 [SIGCHLD] = http_sigchld,
408         },
409 };
410
411 /**
412  * Initiate a HTTP connection
413  *
414  * @v uri               Uniform Resource Identifier
415  * @v buffer            Buffer into which to download file
416  * @v parent            Parent asynchronous operation
417  * @ret rc              Return status code
418  */
419 int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
420         struct http_request *http = NULL;
421         int rc;
422
423         /* Sanity check */
424         if ( ! uri->host ) {
425                 rc = -EINVAL;
426                 goto err;
427         }
428
429         /* Allocate and populate HTTP structure */
430         http = malloc ( sizeof ( *http ) );
431         if ( ! http )
432                 return -ENOMEM;
433         memset ( http, 0, sizeof ( *http ) );
434         http->uri = uri;
435         http->buffer = buffer;
436         async_init ( &http->async, &http_async_operations, parent );
437
438
439 #warning "Quick name resolution hack"
440         extern int dns_resolv ( const char *name,
441                                 struct sockaddr *sa,
442                                 struct async *parent );
443                 
444         if ( ( rc = dns_resolv ( uri->host, &http->server,
445                                  &http->async ) ) != 0 )
446                 goto err;
447
448
449         return 0;
450
451  err:
452         DBGC ( http, "HTTP %p could not create request: %s\n", 
453                http, strerror ( rc ) );
454         async_uninit ( &http->async );
455         free ( http );
456         return rc;
457 }
458
459 /** HTTP download protocol */
460 struct download_protocol http_download_protocol __download_protocol = {
461         .name = "http",
462         .start_download = http_get,
463 };