/* Copyright (C) 2007-2008 The Android Open Source Project ** ** This software is licensed under the terms of the GNU General Public ** License version 2, as published by the Free Software Foundation, and ** may be copied, distributed, and modified under those terms. ** ** This program is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. */ #include "proxy_int.h" #include "proxy_http_int.h" #include "qemu-common.h" #include <errno.h> #include <stdio.h> #include <string.h> #define HTTP_VERSION "1.1" static void http_service_free( HttpService* service ) { PROXY_LOG("%s", __FUNCTION__); if (service->footer != service->footer0) qemu_free(service->footer); qemu_free(service); } static ProxyConnection* http_service_connect( HttpService* service, SocketType sock_type, SockAddress* address ) { /* the HTTP proxy can only handle TCP connections */ if (sock_type != SOCKET_STREAM) return NULL; /* if the client tries to directly connect to the proxy, let it do so */ if (sock_address_equal( address, &service->server_addr )) return NULL; PROXY_LOG("%s: trying to connect to %s", __FUNCTION__, sock_address_to_string(address)); if (sock_address_get_port(address) == 80) { /* use the rewriter for HTTP */ PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); return http_rewriter_connect(service, address); } else { PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); return http_connector_connect(service, address); } } int proxy_http_setup( const char* servername, int servernamelen, int serverport, int num_options, const ProxyOption* options ) { HttpService* service; SockAddress server_addr; const ProxyOption* opt_nocache = NULL; const ProxyOption* opt_keepalive = NULL; const ProxyOption* opt_auth_user = NULL; const ProxyOption* opt_auth_pass = NULL; const ProxyOption* opt_user_agent = NULL; if (servernamelen < 0) servernamelen = strlen(servername); PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d", __FUNCTION__, servernamelen, servername, serverport ); /* resolve server address */ if (proxy_resolve_server(&server_addr, servername, servernamelen, serverport) < 0) { return -1; } /* create service object */ service = qemu_mallocz(sizeof(*service)); if (service == NULL) { PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__); return -1; } service->server_addr = server_addr; /* parse options */ { const ProxyOption* opt = options; const ProxyOption* end = opt + num_options; for ( ; opt < end; opt++ ) { switch (opt->type) { case PROXY_OPTION_HTTP_NOCACHE: opt_nocache = opt; break; case PROXY_OPTION_HTTP_KEEPALIVE: opt_keepalive = opt; break; case PROXY_OPTION_AUTH_USERNAME: opt_auth_user = opt; break; case PROXY_OPTION_AUTH_PASSWORD: opt_auth_pass = opt; break; case PROXY_OPTION_HTTP_USER_AGENT: opt_user_agent = opt; break; default: ; } } } /* prepare footer */ { int wlen; char* p = service->footer0; char* end = p + sizeof(service->footer0); /* no-cache */ if (opt_nocache) { p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n"); if (p >= end) goto FooterOverflow; } /* keep-alive */ if (opt_keepalive) { p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n"); if (p >= end) goto FooterOverflow; } /* authentication */ if (opt_auth_user && opt_auth_pass) { char user_pass[256]; char encoded[512]; int uplen; uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s", opt_auth_user->string_len, opt_auth_user->string, opt_auth_pass->string_len, opt_auth_pass->string ); if (uplen >= sizeof(user_pass)) goto FooterOverflow; wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded)); if (wlen < 0) { PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass); goto FooterOverflow; } p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded); if (p >= end) goto FooterOverflow; } /* user agent */ if (opt_user_agent) { p += snprintf(p, end-p, "User-Agent: %.*s\r\n", opt_user_agent->string_len, opt_user_agent->string); if (p >= end) goto FooterOverflow; } p += snprintf(p, end-p, "\r\n"); if (p >= end) { FooterOverflow: PROXY_LOG( "%s: buffer overflow when creating connection footer", __FUNCTION__); http_service_free(service); return -1; } service->footer = service->footer0; service->footer_len = (p - service->footer); } PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'", __FUNCTION__, service->footer_len, service->footer_len, service->footer ); service->root->opaque = service; service->root->serv_free = (ProxyServiceFreeFunc) http_service_free; service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect; if (proxy_manager_add_service( service->root ) < 0) { PROXY_LOG("%s: could not register service ?", __FUNCTION__); http_service_free(service); return -1; } return 0; }