1 /* Copyright (C) 2007-2008 The Android Open Source Project 2 ** 3 ** This software is licensed under the terms of the GNU General Public 4 ** License version 2, as published by the Free Software Foundation, and 5 ** may be copied, distributed, and modified under those terms. 6 ** 7 ** This program is distributed in the hope that it will be useful, 8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of 9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 ** GNU General Public License for more details. 11 */ 12 #include "proxy_int.h" 13 #include "proxy_http_int.h" 14 #include "qemu-common.h" 15 #include <errno.h> 16 #include <stdio.h> 17 #include <string.h> 18 19 #define HTTP_VERSION "1.1" 20 21 static void 22 http_service_free( HttpService* service ) 23 { 24 PROXY_LOG("%s", __FUNCTION__); 25 if (service->footer != service->footer0) 26 qemu_free(service->footer); 27 qemu_free(service); 28 } 29 30 31 static ProxyConnection* 32 http_service_connect( HttpService* service, 33 SocketType sock_type, 34 SockAddress* address ) 35 { 36 /* the HTTP proxy can only handle TCP connections */ 37 if (sock_type != SOCKET_STREAM) 38 return NULL; 39 40 /* if the client tries to directly connect to the proxy, let it do so */ 41 if (sock_address_equal( address, &service->server_addr )) 42 return NULL; 43 44 PROXY_LOG("%s: trying to connect to %s", 45 __FUNCTION__, sock_address_to_string(address)); 46 47 if (sock_address_get_port(address) == 80) { 48 /* use the rewriter for HTTP */ 49 PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); 50 return http_rewriter_connect(service, address); 51 } else { 52 PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); 53 return http_connector_connect(service, address); 54 } 55 } 56 57 58 int 59 proxy_http_setup( const char* servername, 60 int servernamelen, 61 int serverport, 62 int num_options, 63 const ProxyOption* options ) 64 { 65 HttpService* service; 66 SockAddress server_addr; 67 const ProxyOption* opt_nocache = NULL; 68 const ProxyOption* opt_keepalive = NULL; 69 const ProxyOption* opt_auth_user = NULL; 70 const ProxyOption* opt_auth_pass = NULL; 71 const ProxyOption* opt_user_agent = NULL; 72 73 if (servernamelen < 0) 74 servernamelen = strlen(servername); 75 76 PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d", 77 __FUNCTION__, servernamelen, servername, serverport ); 78 79 /* resolve server address */ 80 if (proxy_resolve_server(&server_addr, servername, 81 servernamelen, serverport) < 0) 82 { 83 return -1; 84 } 85 86 /* create service object */ 87 service = qemu_mallocz(sizeof(*service)); 88 if (service == NULL) { 89 PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__); 90 return -1; 91 } 92 93 service->server_addr = server_addr; 94 95 /* parse options */ 96 { 97 const ProxyOption* opt = options; 98 const ProxyOption* end = opt + num_options; 99 100 for ( ; opt < end; opt++ ) { 101 switch (opt->type) { 102 case PROXY_OPTION_HTTP_NOCACHE: opt_nocache = opt; break; 103 case PROXY_OPTION_HTTP_KEEPALIVE: opt_keepalive = opt; break; 104 case PROXY_OPTION_AUTH_USERNAME: opt_auth_user = opt; break; 105 case PROXY_OPTION_AUTH_PASSWORD: opt_auth_pass = opt; break; 106 case PROXY_OPTION_HTTP_USER_AGENT: opt_user_agent = opt; break; 107 default: ; 108 } 109 } 110 } 111 112 /* prepare footer */ 113 { 114 int wlen; 115 char* p = service->footer0; 116 char* end = p + sizeof(service->footer0); 117 118 /* no-cache */ 119 if (opt_nocache) { 120 p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n"); 121 if (p >= end) goto FooterOverflow; 122 } 123 /* keep-alive */ 124 if (opt_keepalive) { 125 p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n"); 126 if (p >= end) goto FooterOverflow; 127 } 128 /* authentication */ 129 if (opt_auth_user && opt_auth_pass) { 130 char user_pass[256]; 131 char encoded[512]; 132 int uplen; 133 134 uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s", 135 opt_auth_user->string_len, opt_auth_user->string, 136 opt_auth_pass->string_len, opt_auth_pass->string ); 137 138 if (uplen >= sizeof(user_pass)) goto FooterOverflow; 139 140 wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded)); 141 if (wlen < 0) { 142 PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass); 143 goto FooterOverflow; 144 } 145 146 p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded); 147 if (p >= end) goto FooterOverflow; 148 } 149 /* user agent */ 150 if (opt_user_agent) { 151 p += snprintf(p, end-p, "User-Agent: %.*s\r\n", 152 opt_user_agent->string_len, 153 opt_user_agent->string); 154 if (p >= end) goto FooterOverflow; 155 } 156 157 p += snprintf(p, end-p, "\r\n"); 158 159 if (p >= end) { 160 FooterOverflow: 161 PROXY_LOG( "%s: buffer overflow when creating connection footer", 162 __FUNCTION__); 163 http_service_free(service); 164 return -1; 165 } 166 167 service->footer = service->footer0; 168 service->footer_len = (p - service->footer); 169 } 170 171 PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'", 172 __FUNCTION__, service->footer_len, 173 service->footer_len, service->footer ); 174 175 service->root->opaque = service; 176 service->root->serv_free = (ProxyServiceFreeFunc) http_service_free; 177 service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect; 178 179 if (proxy_manager_add_service( service->root ) < 0) { 180 PROXY_LOG("%s: could not register service ?", __FUNCTION__); 181 http_service_free(service); 182 return -1; 183 } 184 return 0; 185 } 186 187