Annotation of qemu/roms/ipxe/src/net/tcp/http.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.