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