18b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project/* Copyright (C) 2007-2008 The Android Open Source Project
28b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
38b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This software is licensed under the terms of the GNU General Public
48b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** License version 2, as published by the Free Software Foundation, and
58b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** may be copied, distributed, and modified under those terms.
68b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project**
78b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** This program is distributed in the hope that it will be useful,
88b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** but WITHOUT ANY WARRANTY; without even the implied warranty of
98b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project** GNU General Public License for more details.
118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project*/
128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "proxy_int.h"
138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "proxy_http_int.h"
148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include "qemu-common.h"
158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <errno.h>
168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <stdio.h>
178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#include <string.h>
188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project#define  HTTP_VERSION  "1.1"
208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic void
228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecthttp_service_free( HttpService*  service )
238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PROXY_LOG("%s", __FUNCTION__);
258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (service->footer != service->footer0)
268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        qemu_free(service->footer);
278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    qemu_free(service);
288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectstatic ProxyConnection*
328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projecthttp_service_connect( HttpService*  service,
338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      SocketType    sock_type,
348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                      SockAddress*  address )
358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* the HTTP proxy can only handle TCP connections */
378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sock_type != SOCKET_STREAM)
388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* if the client tries to directly connect to the proxy, let it do so */
418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sock_address_equal( address, &service->server_addr ))
428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return NULL;
438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PROXY_LOG("%s: trying to connect to %s",
458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project              __FUNCTION__, sock_address_to_string(address));
468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (sock_address_get_port(address) == 80) {
488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* use the rewriter for HTTP */
498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__);
508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return http_rewriter_connect(service, address);
518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    } else {
528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__);
538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return http_connector_connect(service, address);
548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectint
598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Projectproxy_http_setup( const char*         servername,
608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  int                 servernamelen,
618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  int                 serverport,
628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  int                 num_options,
638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                  const ProxyOption*  options )
648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project{
658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    HttpService*        service;
668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    SockAddress         server_addr;
678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const ProxyOption*  opt_nocache   = NULL;
688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const ProxyOption*  opt_keepalive = NULL;
698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const ProxyOption*  opt_auth_user = NULL;
708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const ProxyOption*  opt_auth_pass = NULL;
718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    const ProxyOption*  opt_user_agent = NULL;
728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (servernamelen < 0)
748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        servernamelen = strlen(servername);
758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d",
778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               __FUNCTION__, servernamelen, servername, serverport );
788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* resolve server address */
808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (proxy_resolve_server(&server_addr, servername,
818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                             servernamelen, serverport) < 0)
828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* create service object */
878b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    service = qemu_mallocz(sizeof(*service));
888b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (service == NULL) {
898b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__);
908b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
918b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
928b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
938b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    service->server_addr = server_addr;
948b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
958b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* parse options */
968b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
978b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        const ProxyOption*  opt = options;
988b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        const ProxyOption*  end = opt + num_options;
998b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1008b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        for ( ; opt < end; opt++ ) {
1018b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            switch (opt->type) {
1028b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case PROXY_OPTION_HTTP_NOCACHE:     opt_nocache    = opt; break;
1038b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case PROXY_OPTION_HTTP_KEEPALIVE:   opt_keepalive  = opt; break;
1048b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case PROXY_OPTION_AUTH_USERNAME:    opt_auth_user  = opt; break;
1058b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case PROXY_OPTION_AUTH_PASSWORD:    opt_auth_pass  = opt; break;
1068b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                case PROXY_OPTION_HTTP_USER_AGENT:  opt_user_agent = opt; break;
1078b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                default: ;
1088b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1098b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1108b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1118b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1128b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    /* prepare footer */
1138b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    {
1148b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        int    wlen;
1158b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        char*  p    = service->footer0;
1168b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        char*  end  = p + sizeof(service->footer0);
1178b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1188b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* no-cache */
1198b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (opt_nocache) {
1208b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n");
1218b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (p >= end) goto FooterOverflow;
1228b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1238b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* keep-alive */
1248b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (opt_keepalive) {
1258b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n");
1268b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (p >= end) goto FooterOverflow;
1278b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1288b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* authentication */
1298b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (opt_auth_user && opt_auth_pass) {
1308b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            char  user_pass[256];
1318b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            char  encoded[512];
1328b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            int   uplen;
1338b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1348b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s",
1358b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              opt_auth_user->string_len, opt_auth_user->string,
1368b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                              opt_auth_pass->string_len, opt_auth_pass->string );
1378b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1388b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (uplen >= sizeof(user_pass)) goto FooterOverflow;
1398b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1408b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded));
1418b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (wlen < 0) {
1428b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass);
1438b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                goto FooterOverflow;
1448b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            }
1458b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1468b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded);
1478b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (p >= end) goto FooterOverflow;
1488b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1498b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        /* user agent */
1508b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (opt_user_agent) {
1518b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            p += snprintf(p, end-p, "User-Agent: %.*s\r\n",
1528b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                          opt_user_agent->string_len,
1538b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                          opt_user_agent->string);
1548b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            if (p >= end) goto FooterOverflow;
1558b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1568b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1578b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        p += snprintf(p, end-p, "\r\n");
1588b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1598b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        if (p >= end) {
1608b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        FooterOverflow:
1618b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            PROXY_LOG( "%s: buffer overflow when creating connection footer",
1628b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project                       __FUNCTION__);
1638b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            http_service_free(service);
1648b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project            return -1;
1658b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        }
1668b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1678b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        service->footer     = service->footer0;
1688b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        service->footer_len = (p - service->footer);
1698b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1708b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1718b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'",
1728b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               __FUNCTION__, service->footer_len,
1738b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project               service->footer_len, service->footer );
1748b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1758b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    service->root->opaque       = service;
1768b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    service->root->serv_free    = (ProxyServiceFreeFunc)    http_service_free;
1778b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect;
1788b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
1798b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    if (proxy_manager_add_service( service->root ) < 0) {
1808b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        PROXY_LOG("%s: could not register service ?", __FUNCTION__);
1818b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        http_service_free(service);
1828b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project        return -1;
1838b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    }
1848b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project    return 0;
1858b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project}
1868b23a6c7e1aee255004dd19098d4c2462b61b849The Android Open Source Project
187