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