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