Allow queries in GET requests
[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 <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/async.h>
35 #include <gpxe/uri.h>
36 #include <gpxe/buffer.h>
37 #include <gpxe/download.h>
38 #include <gpxe/resolv.h>
39 #include <gpxe/tcp.h>
40 #include <gpxe/tls.h>
41 #include <gpxe/http.h>
42
43 static struct async_operations http_async_operations;
44
45 static inline struct http_request *
46 stream_to_http ( struct stream_application *app ) {
47         return container_of ( app, struct http_request, stream );
48 }
49
50 /**
51  * Mark HTTP request as complete
52  *
53  * @v http              HTTP request
54  * @v rc                Return status code
55  *
56  */
57 static void http_done ( struct http_request *http, int rc ) {
58
59         /* Close stream connection */
60         stream_close ( &http->stream );
61
62         /* Prevent further processing of any current packet */
63         http->rx_state = HTTP_RX_DEAD;
64
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
69          * isn't correct, flag an error
70          */
71         if ( http->content_length &&
72              ( http->content_length != http->buffer->fill ) ) {
73                 DBGC ( http, "HTTP %p incorrect length %zd, should be %zd\n",
74                        http, http->buffer->fill, http->content_length );
75                 rc = -EIO;
76         }
77
78         /* Mark async operation as complete */
79         async_done ( &http->async, rc );
80 }
81
82 /**
83  * Convert HTTP response code to return status code
84  *
85  * @v response          HTTP response code
86  * @ret rc              Return status code
87  */
88 static int http_response_to_rc ( unsigned int response ) {
89         switch ( response ) {
90         case 200:
91                 return 0;
92         case 404:
93                 return -ENOENT;
94         case 403:
95                 return -EPERM;
96         default:
97                 return -EIO;
98         }
99 }
100
101 /**
102  * Handle HTTP response
103  *
104  * @v http              HTTP request
105  * @v response          HTTP response
106  */
107 static void http_rx_response ( struct http_request *http, char *response ) {
108         char *spc;
109         int rc = -EIO;
110
111         DBGC ( http, "HTTP %p response \"%s\"\n", http, response );
112
113         /* Check response starts with "HTTP/" */
114         if ( strncmp ( response, "HTTP/", 5 ) != 0 )
115                 goto err;
116
117         /* Locate and check response code */
118         spc = strchr ( response, ' ' );
119         if ( ! spc )
120                 goto err;
121         http->response = strtoul ( spc, NULL, 10 );
122         if ( ( rc = http_response_to_rc ( http->response ) ) != 0 )
123                 goto err;
124
125         /* Move to received headers */
126         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;
133 }
134
135 /**
136  * Handle HTTP Content-Length header
137  *
138  * @v http              HTTP request
139  * @v value             HTTP header value
140  * @ret rc              Return status code
141  */
142 static int http_rx_content_length ( struct http_request *http,
143                                     const char *value ) {
144         char *endp;
145         int rc;
146
147         http->content_length = strtoul ( value, &endp, 10 );
148         if ( *endp != '\0' ) {
149                 DBGC ( http, "HTTP %p invalid Content-Length \"%s\"\n",
150                        http, value );
151                 return -EIO;
152         }
153
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         }
162
163         return 0;
164 }
165
166 /**
167  * An HTTP header handler
168  *
169  */
170 struct http_header_handler {
171         /** Name (e.g. "Content-Length") */
172         const char *header;
173         /** Handle received header
174          *
175          * @v http      HTTP request
176          * @v value     HTTP header value
177          * @ret rc      Return status code
178          *
179          * If an error is returned, the download will be aborted.
180          */
181         int ( * rx ) ( struct http_request *http, const char *value );
182 };
183
184 /** List of HTTP header handlers */
185 struct http_header_handler http_header_handlers[] = {
186         {
187                 .header = "Content-Length",
188                 .rx = http_rx_content_length,
189         },
190         { NULL, NULL }
191 };
192
193 /**
194  * Handle HTTP header
195  *
196  * @v http              HTTP request
197  * @v header            HTTP header
198  */
199 static void http_rx_header ( struct http_request *http, char *header ) {
200         struct http_header_handler *handler;
201         char *separator;
202         char *value;
203         int rc = -EIO;
204
205         /* An empty header line marks the transition to the data phase */
206         if ( ! header[0] ) {
207                 DBGC ( http, "HTTP %p start of data\n", http );
208                 empty_line_buffer ( &http->linebuf );
209                 http->rx_state = HTTP_RX_DATA;
210                 return;
211         }
212
213         DBGC ( http, "HTTP %p header \"%s\"\n", http, header );
214
215         /* Split header at the ": " */
216         separator = strstr ( header, ": " );
217         if ( ! separator )
218                 goto err;
219         *separator = '\0';
220         value = ( separator + 2 );
221
222         /* Hand off to header handler, if one exists */
223         for ( handler = http_header_handlers ; handler->header ; handler++ ) {
224                 if ( strcasecmp ( header, handler->header ) == 0 ) {
225                         if ( ( rc = handler->rx ( http, value ) ) != 0 )
226                                 goto err;
227                         break;
228                 }
229         }
230         return;
231
232  err:
233         DBGC ( http, "HTTP %p bad header\n", http );
234         http_done ( http, rc );
235         return;
236 }
237
238 /**
239  * Handle new data arriving via HTTP connection in the data phase
240  *
241  * @v http              HTTP request
242  * @v data              New data
243  * @v len               Length of new data
244  */
245 static void http_rx_data ( struct http_request *http,
246                            const char *data, size_t len ) {
247         int rc;
248
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         }
257
258         /* Update progress */
259         http->async.completed = http->buffer->fill;
260         http->async.total = http->content_length;
261
262         /* If we have reached the content-length, stop now */
263         if ( http->content_length &&
264              ( http->buffer->fill >= http->content_length ) ) {
265                 http_done ( http, 0 );
266         }
267 }
268
269 /**
270  * Handle new data arriving via HTTP connection
271  *
272  * @v http              HTTP request
273  * @v data              New data
274  * @v len               Length of new data
275  */
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;
280         char *line;
281         int rc;
282
283         while ( len ) {
284                 if ( http->rx_state == HTTP_RX_DEAD ) {
285                         /* Do no further processing */
286                         return;
287                 } else if ( http->rx_state == HTTP_RX_DATA ) {
288                         /* Once we're into the data phase, just fill
289                          * the data buffer
290                          */
291                         http_rx_data ( http, buf, len );
292                         return;
293                 } else {
294                         /* In the other phases, buffer and process a
295                          * line at a time
296                          */
297                         if ( ( rc = line_buffer ( &http->linebuf, &buf,
298                                                   &len ) ) != 0 ) {
299                                 DBGC ( http, "HTTP %p could not buffer line: "
300                                        "%s\n", http, strerror ( rc ) );
301                                 http_done ( http, rc );
302                                 return;
303                         }
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                                 }
316                         }
317                 }
318         }
319 }
320
321 /**
322  * Send HTTP data
323  *
324  * @v app               Stream application
325  * @v buf               Temporary data buffer
326  * @v len               Length of temporary data buffer
327  */
328 static void http_senddata ( struct stream_application *app,
329                             void *buf, size_t len ) {
330         struct http_request *http = stream_to_http ( app );
331         const char *path = http->uri->path;
332         const char *host = http->uri->host;
333         const char *query = http->uri->query;
334
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 ) );
347 }
348
349 /**
350  * HTTP data acknowledged
351  *
352  * @v app               Stream application
353  * @v len               Length of acknowledged data
354  */
355 static void http_acked ( struct stream_application *app, size_t len ) {
356         struct http_request *http = stream_to_http ( app );
357
358         http->tx_offset += len;
359 }
360
361 /**
362  * HTTP connection closed by network stack
363  *
364  * @v app               Stream application
365  */
366 static void http_closed ( struct stream_application *app, int rc ) {
367         struct http_request *http = stream_to_http ( app );
368
369         DBGC ( http, "HTTP %p connection closed: %s\n",
370                http, strerror ( rc ) );
371         
372         http_done ( http, rc );
373 }
374
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,
381 };
382
383 /**
384  * Initiate a HTTP connection
385  *
386  * @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
390  */
391 int http_get ( struct uri *uri, struct buffer *buffer, struct async *parent ) {
392         struct http_request *http = NULL;
393         struct sockaddr_tcpip *st;
394         int rc;
395
396         /* Allocate and populate HTTP structure */
397         http = malloc ( sizeof ( *http ) );
398         if ( ! http )
399                 return -ENOMEM;
400         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 )
410                 goto err;
411         if ( strcmp ( http->uri->scheme, "https" ) == 0 ) {
412                 st->st_port = htons ( uri_port ( http->uri, HTTPS_PORT ) );
413                 if ( ( rc = add_tls ( &http->stream ) ) != 0 )
414                         goto err;
415         }
416
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
423         return 0;
424
425  err:
426         DBGC ( http, "HTTP %p could not create request: %s\n", 
427                http, strerror ( rc ) );
428         async_uninit ( &http->async );
429         free ( http );
430         return rc;
431 }
432
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,
481 };
482
483 /** HTTPS download protocol */
484 struct download_protocol https_download_protocol __download_protocol = {
485         .name = "https",
486         .start_download = http_get,
487 };