Home | History | Annotate | Download | only in proxy
      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