The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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) |
David 'Digit' Turner | aa8236d | 2014-01-10 17:02:29 +0100 | [diff] [blame] | 26 | g_free(service->footer); |
| 27 | g_free(service); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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 */ |
David 'Digit' Turner | aa8236d | 2014-01-10 17:02:29 +0100 | [diff] [blame] | 87 | service = g_malloc0(sizeof(*service)); |
The Android Open Source Project | 8b23a6c | 2009-03-03 19:30:32 -0800 | [diff] [blame] | 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 | |