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
21static void
22http_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
31static ProxyConnection*
32http_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
58int
59proxy_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