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
http_service_free(HttpService * service)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*
http_service_connect(HttpService * service,SocketType sock_type,SockAddress * address)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
proxy_http_setup(const char * servername,int servernamelen,int serverport,int num_options,const ProxyOption * options)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