18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "proxy_http_int.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <errno.h>
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <stdio.h>
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <string.h>
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h"
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* A HttpConnector implements a non-HTTP proxied connection
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * through the CONNECT method. Many firewalls are configured
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * to reject these for port 80, so these connections should
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project * use a HttpRewriter instead.
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project */
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef enum {
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    STATE_NONE = 0,
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    STATE_CONNECTING,           /* connecting to the server */
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    STATE_SEND_HEADER,          /* connected, sending header to the server */
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    STATE_RECEIVE_ANSWER_LINE1,
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    STATE_RECEIVE_ANSWER_LINE2  /* connected, reading server's answer */
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} ConnectorState;
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecttypedef struct Connection {
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ProxyConnection  root[1];
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ConnectorState   state;
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} Connection;
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconnection_free( ProxyConnection*  root )
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    proxy_connection_done(root);
42aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    g_free(root);
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  HTTP_VERSION  "1.1"
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic int
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconnection_init( Connection*  conn )
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    HttpService*      service = (HttpService*) conn->root->service;
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    ProxyConnection*  root    = conn->root;
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    stralloc_t*       str     = root->str;
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    proxy_connection_rewind(root);
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    stralloc_add_format(str, "CONNECT %s HTTP/" HTTP_VERSION "\r\n",
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        sock_address_to_string(&root->address));
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    stralloc_add_bytes(str, service->footer, service->footer_len);
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!socket_connect( root->socket, &service->server_addr )) {
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* immediate connection ?? */
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        conn->state = STATE_SEND_HEADER;
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PROXY_LOG("%s: immediate connection", root->name);
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    else {
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (errno == EINPROGRESS || errno == EWOULDBLOCK) {
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            conn->state = STATE_CONNECTING;
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            PROXY_LOG("%s: connecting", root->name);
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        else {
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            PROXY_LOG("%s: cannot connect to proxy: %s", root->name, errno_str);
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return -1;
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconnection_select( ProxyConnection*   root,
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                   ProxySelect*       sel )
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    unsigned     flags;
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Connection*  conn = (Connection*)root;
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (conn->state) {
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_RECEIVE_ANSWER_LINE1:
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_RECEIVE_ANSWER_LINE2:
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            flags = PROXY_SELECT_READ;
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_CONNECTING:
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_SEND_HEADER:
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            flags = PROXY_SELECT_WRITE;
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            flags = 0;
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    };
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    proxy_select_set(sel, root->socket, flags);
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectconnection_poll( ProxyConnection*   root,
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                 ProxySelect*       sel )
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    DataStatus   ret  = DATA_NEED_MORE;
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Connection*  conn = (Connection*)root;
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int          fd   = root->socket;
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (!proxy_select_poll(sel, fd))
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    switch (conn->state)
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_CONNECTING:
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            PROXY_LOG("%s: connected to http proxy, sending header", root->name);
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            conn->state = STATE_SEND_HEADER;
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_SEND_HEADER:
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = proxy_connection_send(root, fd);
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ret == DATA_COMPLETED) {
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                conn->state = STATE_RECEIVE_ANSWER_LINE1;
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                PROXY_LOG("%s: header sent, receiving first answer line", root->name);
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_RECEIVE_ANSWER_LINE1:
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        case STATE_RECEIVE_ANSWER_LINE2:
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            ret = proxy_connection_receive_line(root, root->socket);
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (ret == DATA_COMPLETED) {
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                if (conn->state == STATE_RECEIVE_ANSWER_LINE1) {
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    int  http1, http2, codenum;
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    const char*  line = root->str->s;
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if ( sscanf(line, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) {
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        PROXY_LOG( "%s: invalid answer from proxy: '%s'",
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                    root->name, line );
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        ret = DATA_ERROR;
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        break;
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    }
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* success is 2xx */
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    if (codenum/2 != 100) {
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        PROXY_LOG( "%s: connection refused, error=%d",
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                                    root->name, codenum );
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        proxy_connection_free( root, 0, PROXY_EVENT_CONNECTION_REFUSED );
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        return;
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    }
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    PROXY_LOG("%s: receiving second answer line", root->name);
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    conn->state = STATE_RECEIVE_ANSWER_LINE2;
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    proxy_connection_rewind(root);
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                } else {
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    /* ok, we're connected */
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    PROXY_LOG("%s: connection succeeded", root->name);
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                    proxy_connection_free( root, 1, PROXY_EVENT_CONNECTED );
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                }
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            break;
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        default:
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            PROXY_LOG("%s: invalid state for read event: %d", root->name, conn->state);
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (ret == DATA_ERROR) {
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        proxy_connection_free( root, 0, PROXY_EVENT_SERVER_ERROR );
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source ProjectProxyConnection*
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecthttp_connector_connect( HttpService*  service,
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                        SockAddress*  address )
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    Connection*  conn;
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    int          s;
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    s = socket_create_inet( SOCKET_STREAM );
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (s < 0)
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
186aa8236dc1b1ea300ab18716db5b8fab42aca3ca7David 'Digit' Turner    conn = g_malloc0(sizeof(*conn));
1878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (conn == NULL) {
1888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        socket_close(s);
1898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
1908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    proxy_connection_init( conn->root, s, address, service->root,
1938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           connection_free,
1948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           connection_select,
1958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                           connection_poll );
1968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if ( connection_init( conn ) < 0 ) {
1988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        connection_free( conn->root );
1998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
2008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
2018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
2028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return conn->root;
2038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
204