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_int.h" 138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "proxy_http_int.h" 148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h" 158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <errno.h> 168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <stdio.h> 178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <string.h> 188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define HTTP_VERSION "1.1" 208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void 228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecthttp_service_free( HttpService* service ) 238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s", __FUNCTION__); 258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (service->footer != service->footer0) 268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(service->footer); 278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project qemu_free(service); 288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic ProxyConnection* 328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecthttp_service_connect( HttpService* service, 338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SocketType sock_type, 348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SockAddress* address ) 358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* the HTTP proxy can only handle TCP connections */ 378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (sock_type != SOCKET_STREAM) 388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* if the client tries to directly connect to the proxy, let it do so */ 418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (sock_address_equal( address, &service->server_addr )) 428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return NULL; 438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s: trying to connect to %s", 458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__, sock_address_to_string(address)); 468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (sock_address_get_port(address) == 80) { 488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* use the rewriter for HTTP */ 498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); 508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return http_rewriter_connect(service, address); 518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } else { 528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); 538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return http_connector_connect(service, address); 548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint 598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectproxy_http_setup( const char* servername, 608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int servernamelen, 618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int serverport, 628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int num_options, 638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* options ) 648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{ 658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project HttpService* service; 668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project SockAddress server_addr; 678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt_nocache = NULL; 688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt_keepalive = NULL; 698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt_auth_user = NULL; 708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt_auth_pass = NULL; 718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt_user_agent = NULL; 728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (servernamelen < 0) 748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project servernamelen = strlen(servername); 758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d", 778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__, servernamelen, servername, serverport ); 788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* resolve server address */ 808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (proxy_resolve_server(&server_addr, servername, 818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project servernamelen, serverport) < 0) 828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* create service object */ 878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service = qemu_mallocz(sizeof(*service)); 888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (service == NULL) { 898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__); 908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->server_addr = server_addr; 948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* parse options */ 968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* opt = options; 988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project const ProxyOption* end = opt + num_options; 998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project for ( ; opt < end; opt++ ) { 1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project switch (opt->type) { 1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case PROXY_OPTION_HTTP_NOCACHE: opt_nocache = opt; break; 1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case PROXY_OPTION_HTTP_KEEPALIVE: opt_keepalive = opt; break; 1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case PROXY_OPTION_AUTH_USERNAME: opt_auth_user = opt; break; 1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case PROXY_OPTION_AUTH_PASSWORD: opt_auth_pass = opt; break; 1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project case PROXY_OPTION_HTTP_USER_AGENT: opt_user_agent = opt; break; 1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project default: ; 1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* prepare footer */ 1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project { 1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int wlen; 1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char* p = service->footer0; 1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char* end = p + sizeof(service->footer0); 1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* no-cache */ 1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (opt_nocache) { 1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n"); 1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (p >= end) goto FooterOverflow; 1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* keep-alive */ 1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (opt_keepalive) { 1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n"); 1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (p >= end) goto FooterOverflow; 1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* authentication */ 1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (opt_auth_user && opt_auth_pass) { 1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char user_pass[256]; 1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project char encoded[512]; 1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project int uplen; 1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s", 1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project opt_auth_user->string_len, opt_auth_user->string, 1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project opt_auth_pass->string_len, opt_auth_pass->string ); 1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (uplen >= sizeof(user_pass)) goto FooterOverflow; 1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded)); 1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (wlen < 0) { 1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass); 1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project goto FooterOverflow; 1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded); 1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (p >= end) goto FooterOverflow; 1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project /* user agent */ 1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (opt_user_agent) { 1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += snprintf(p, end-p, "User-Agent: %.*s\r\n", 1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project opt_user_agent->string_len, 1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project opt_user_agent->string); 1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (p >= end) goto FooterOverflow; 1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project p += snprintf(p, end-p, "\r\n"); 1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (p >= end) { 1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project FooterOverflow: 1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG( "%s: buffer overflow when creating connection footer", 1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__); 1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project http_service_free(service); 1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->footer = service->footer0; 1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->footer_len = (p - service->footer); 1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'", 1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project __FUNCTION__, service->footer_len, 1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->footer_len, service->footer ); 1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->root->opaque = service; 1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->root->serv_free = (ProxyServiceFreeFunc) http_service_free; 1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect; 1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project if (proxy_manager_add_service( service->root ) < 0) { 1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project PROXY_LOG("%s: could not register service ?", __FUNCTION__); 1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project http_service_free(service); 1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return -1; 1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project } 1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project return 0; 1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project} 1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project 187