From f721e3ac031f892af46f255a47d7f54a91317b30 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:35 -0800 Subject: auto import from //depot/cupcake/@135843 --- proxy/proxy_common.c | 532 -------------------- proxy/proxy_common.h | 88 ---- proxy/proxy_http.c | 186 ------- proxy/proxy_http.h | 24 - proxy/proxy_http_connector.c | 203 -------- proxy/proxy_http_int.h | 38 -- proxy/proxy_http_rewriter.c | 1125 ------------------------------------------ proxy/proxy_int.h | 201 -------- 8 files changed, 2397 deletions(-) delete mode 100644 proxy/proxy_common.c delete mode 100644 proxy/proxy_common.h delete mode 100644 proxy/proxy_http.c delete mode 100644 proxy/proxy_http.h delete mode 100644 proxy/proxy_http_connector.c delete mode 100644 proxy/proxy_http_int.h delete mode 100644 proxy/proxy_http_rewriter.c delete mode 100644 proxy/proxy_int.h (limited to 'proxy') diff --git a/proxy/proxy_common.c b/proxy/proxy_common.c deleted file mode 100644 index 7794a62..0000000 --- a/proxy/proxy_common.c +++ /dev/null @@ -1,532 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "proxy_int.h" -#include "sockets.h" -#include -#include -#include -#include -#include "android/utils/misc.h" -#include "android/utils/system.h" -#include - -int proxy_log = 0; - -void -proxy_LOG(const char* fmt, ...) -{ - va_list args; - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); -} - -void -proxy_set_verbose(int mode) -{ - proxy_log = mode; -} - -/** Global connection list - **/ - -static ProxyConnection s_connections[1]; - -#define MAX_HEX_DUMP 512 - -static void -hex_dump( void* base, int size, const char* prefix ) -{ - STRALLOC_DEFINE(s); - if (size > MAX_HEX_DUMP) - size = MAX_HEX_DUMP; - stralloc_add_hexdump(s, base, size, prefix); - proxy_LOG( "%s", stralloc_cstr(s) ); - stralloc_reset(s); -} - -void -proxy_connection_init( ProxyConnection* conn, - int socket, - SockAddress* address, - ProxyService* service, - ProxyConnectionFreeFunc conn_free, - ProxyConnectionSelectFunc conn_select, - ProxyConnectionPollFunc conn_poll ) -{ - conn->socket = socket; - conn->address = address[0]; - conn->service = service; - conn->next = NULL; - - conn->conn_free = conn_free; - conn->conn_select = conn_select; - conn->conn_poll = conn_poll; - - socket_set_nonblock(socket); - - { - SocketType type = socket_get_type(socket); - - snprintf( conn->name, sizeof(conn->name), - "%s:%s(%d)", - (type == SOCKET_STREAM) ? "tcp" : "udp", - sock_address_to_string(address), socket ); - - /* just in case */ - conn->name[sizeof(conn->name)-1] = 0; - } - - stralloc_reset(conn->str); - conn->str_pos = 0; -} - -void -proxy_connection_done( ProxyConnection* conn ) -{ - stralloc_reset( conn->str ); - if (conn->socket >= 0) { - socket_close(conn->socket); - conn->socket = -1; - } -} - - -void -proxy_connection_rewind( ProxyConnection* conn ) -{ - stralloc_t* str = conn->str; - - /* only keep a small buffer in the heap */ - conn->str_pos = 0; - str->n = 0; - if (str->a > 1024) - stralloc_reset(str); -} - -DataStatus -proxy_connection_send( ProxyConnection* conn, int fd ) -{ - stralloc_t* str = conn->str; - int avail = str->n - conn->str_pos; - - conn->str_sent = 0; - - if (avail <= 0) - return 1; - - if (proxy_log) { - PROXY_LOG("%s: sending %d bytes:", conn->name, avail ); - hex_dump( str->s + conn->str_pos, avail, ">> " ); - } - - while (avail > 0) { - int n = socket_send(fd, str->s + conn->str_pos, avail); - if (n == 0) { - PROXY_LOG("%s: connection reset by peer (send)", - conn->name); - return DATA_ERROR; - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) - return DATA_NEED_MORE; - - PROXY_LOG("%s: error: %s", conn->name, errno_str); - return DATA_ERROR; - } - conn->str_pos += n; - conn->str_sent += n; - avail -= n; - } - - proxy_connection_rewind(conn); - return DATA_COMPLETED; -} - - -DataStatus -proxy_connection_receive( ProxyConnection* conn, int fd, int wanted ) -{ - stralloc_t* str = conn->str; - - conn->str_recv = 0; - - while (wanted > 0) { - int n; - - stralloc_readyplus( str, wanted ); - n = socket_recv(fd, str->s + str->n, wanted); - if (n == 0) { - PROXY_LOG("%s: connection reset by peer (receive)", - conn->name); - return DATA_ERROR; - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) - return DATA_NEED_MORE; - - PROXY_LOG("%s: error: %s", conn->name, errno_str); - return DATA_ERROR; - } - - if (proxy_log) { - PROXY_LOG("%s: received %d bytes:", conn->name, n ); - hex_dump( str->s + str->n, n, "<< " ); - } - - str->n += n; - wanted -= n; - conn->str_recv += n; - } - return DATA_COMPLETED; -} - - -DataStatus -proxy_connection_receive_line( ProxyConnection* conn, int fd ) -{ - stralloc_t* str = conn->str; - - for (;;) { - char c; - int n = socket_recv(fd, &c, 1); - if (n == 0) { - PROXY_LOG("%s: disconnected from server", conn->name ); - return DATA_ERROR; - } - if (n < 0) { - if (errno == EWOULDBLOCK || errno == EAGAIN) { - PROXY_LOG("%s: blocked", conn->name); - return DATA_NEED_MORE; - } - PROXY_LOG("%s: error: %s", conn->name, errno_str); - return DATA_ERROR; - } - - stralloc_add_c(str, c); - if (c == '\n') { - str->s[--str->n] = 0; - if (str->n > 0 && str->s[str->n-1] == '\r') - str->s[--str->n] = 0; - - PROXY_LOG("%s: received '%s'", conn->name, - quote_bytes(str->s, str->n)); - return DATA_COMPLETED; - } - } -} - -static void -proxy_connection_insert( ProxyConnection* conn, ProxyConnection* after ) -{ - conn->next = after->next; - after->next->prev = conn; - after->next = conn; - conn->prev = after; -} - -static void -proxy_connection_remove( ProxyConnection* conn ) -{ - conn->prev->next = conn->next; - conn->next->prev = conn->prev; - - conn->next = conn->prev = conn; -} - -/** Global service list - **/ - -#define MAX_SERVICES 4 - -static ProxyService* s_services[ MAX_SERVICES ]; -static int s_num_services; -static int s_init; - -static void proxy_manager_atexit( void ); - -static void -proxy_manager_init(void) -{ - s_init = 1; - s_connections->next = s_connections; - s_connections->prev = s_connections; - atexit( proxy_manager_atexit ); -} - - -extern int -proxy_manager_add_service( ProxyService* service ) -{ - if (!service || s_num_services >= MAX_SERVICES) - return -1; - - if (!s_init) - proxy_manager_init(); - - s_services[s_num_services++] = service; - return 0; -} - - -extern void -proxy_manager_atexit( void ) -{ - ProxyConnection* conn = s_connections->next; - int n; - - /* free all proxy connections */ - while (conn != s_connections) { - ProxyConnection* next = conn->next; - conn->conn_free( conn ); - conn = next; - } - conn->next = conn; - conn->prev = conn; - - /* free all proxy services */ - for (n = s_num_services; n-- > 0;) { - ProxyService* service = s_services[n]; - service->serv_free( service->opaque ); - } - s_num_services = 0; -} - - -void -proxy_connection_free( ProxyConnection* conn, - int keep_alive, - ProxyEvent event ) -{ - if (conn) { - int fd = conn->socket; - - proxy_connection_remove(conn); - - if (event != PROXY_EVENT_NONE) - conn->ev_func( conn->ev_opaque, fd, event ); - - if (keep_alive) - conn->socket = -1; - - conn->conn_free(conn); - } -} - - -int -proxy_manager_add( SockAddress* address, - SocketType sock_type, - ProxyEventFunc ev_func, - void* ev_opaque ) -{ - int n; - - if (!s_init) { - proxy_manager_init(); - } - - for (n = 0; n < s_num_services; n++) { - ProxyService* service = s_services[n]; - ProxyConnection* conn = service->serv_connect( service->opaque, - sock_type, - address ); - if (conn != NULL) { - conn->ev_func = ev_func; - conn->ev_opaque = ev_opaque; - proxy_connection_insert(conn, s_connections->prev); - return 0; - } - } - return -1; -} - - -/* remove an on-going proxified socket connection from the manager's list. - * this is only necessary when the socket connection must be canceled before - * the connection accept/refusal occured - */ -void -proxy_manager_del( void* ev_opaque ) -{ - ProxyConnection* conn = s_connections->next; - for ( ; conn != s_connections; conn = conn->next ) { - if (conn->ev_opaque == ev_opaque) { - proxy_connection_remove(conn); - conn->conn_free(conn); - return; - } - } -} - -void -proxy_select_set( ProxySelect* sel, - int fd, - unsigned flags ) -{ - if (fd < 0 || !flags) - return; - - if (*sel->pcount < fd+1) - *sel->pcount = fd+1; - - if (flags & PROXY_SELECT_READ) { - FD_SET( fd, sel->reads ); - } else { - FD_CLR( fd, sel->reads ); - } - if (flags & PROXY_SELECT_WRITE) { - FD_SET( fd, sel->writes ); - } else { - FD_CLR( fd, sel->writes ); - } - if (flags & PROXY_SELECT_ERROR) { - FD_SET( fd, sel->errors ); - } else { - FD_CLR( fd, sel->errors ); - } -} - -unsigned -proxy_select_poll( ProxySelect* sel, int fd ) -{ - unsigned flags = 0; - - if (fd >= 0) { - if ( FD_ISSET(fd, sel->reads) ) - flags |= PROXY_SELECT_READ; - if ( FD_ISSET(fd, sel->writes) ) - flags |= PROXY_SELECT_WRITE; - if ( FD_ISSET(fd, sel->errors) ) - flags |= PROXY_SELECT_ERROR; - } - return flags; -} - -/* this function is called to update the select file descriptor sets - * with those of the proxified connection sockets that are currently managed */ -void -proxy_manager_select_fill( int *pcount, fd_set* read_fds, fd_set* write_fds, fd_set* err_fds) -{ - ProxyConnection* conn; - ProxySelect sel[1]; - - if (!s_init) - proxy_manager_init(); - - sel->pcount = pcount; - sel->reads = read_fds; - sel->writes = write_fds; - sel->errors = err_fds; - - conn = s_connections->next; - while (conn != s_connections) { - ProxyConnection* next = conn->next; - conn->conn_select(conn, sel); - conn = next; - } -} - -/* this function is called to act on proxified connection sockets when network events arrive */ -void -proxy_manager_poll( fd_set* read_fds, fd_set* write_fds, fd_set* err_fds ) -{ - ProxyConnection* conn = s_connections->next; - ProxySelect sel[1]; - - sel->pcount = NULL; - sel->reads = read_fds; - sel->writes = write_fds; - sel->errors = err_fds; - - while (conn != s_connections) { - ProxyConnection* next = conn->next; - conn->conn_poll( conn, sel ); - conn = next; - } -} - - -int -proxy_base64_encode( const char* src, int srclen, - char* dst, int dstlen ) -{ - static const char cb64[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - const char* srcend = src + srclen; - int result = 0; - - while (src+3 <= srcend && result+4 <= dstlen) - { - dst[result+0] = cb64[ src[0] >> 2 ]; - dst[result+1] = cb64[ ((src[0] & 3) << 4) | ((src[1] & 0xf0) >> 4) ]; - dst[result+2] = cb64[ ((src[1] & 0xf) << 2) | ((src[2] & 0xc0) >> 6) ]; - dst[result+3] = cb64[ src[2] & 0x3f ]; - src += 3; - result += 4; - } - - if (src < srcend) { - unsigned char in[4]; - - if (result+4 > dstlen) - return -1; - - in[0] = src[0]; - in[1] = src+1 < srcend ? src[1] : 0; - in[2] = src+2 < srcend ? src[2] : 0; - - dst[result+0] = cb64[ in[0] >> 2 ]; - dst[result+1] = cb64[ ((in[0] & 3) << 4) | ((in[1] & 0xf0) >> 4) ]; - dst[result+2] = (unsigned char) (src+1 < srcend ? cb64[ ((in[1] & 0xf) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); - dst[result+3] = (unsigned char) (src+2 < srcend ? cb64[ in[2] & 0x3f ] : '='); - result += 4; - } - return result; -} - -int -proxy_resolve_server( SockAddress* addr, - const char* servername, - int servernamelen, - int serverport ) -{ - char name0[64], *name = name0; - int result = -1; - - if (servernamelen < 0) - servernamelen = strlen(servername); - - if (servernamelen >= sizeof(name0)) { - AARRAY_NEW(name, servernamelen+1); - } - - memcpy(name, servername, servernamelen); - name[servernamelen] = 0; - - if (sock_address_init_resolve( addr, name, serverport, 0 ) < 0) { - PROXY_LOG("%s: can't resolve proxy server name '%s'", - __FUNCTION__, name); - goto Exit; - } - - PROXY_LOG("server name '%s' resolved to %s", name, sock_address_to_string(addr)); - result = 0; - -Exit: - if (name != name0) - AFREE(name); - - return result; -} - - diff --git a/proxy/proxy_common.h b/proxy/proxy_common.h deleted file mode 100644 index 78eddd8..0000000 --- a/proxy/proxy_common.h +++ /dev/null @@ -1,88 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _PROXY_COMMON_H_ -#define _PROXY_COMMON_H_ - -#include "sockets.h" - -#ifdef _WIN32 -#include -#else -#include -#endif - -/* types and definitions used by all proxy connections */ - -typedef enum { - PROXY_EVENT_NONE, - PROXY_EVENT_CONNECTED, - PROXY_EVENT_CONNECTION_REFUSED, - PROXY_EVENT_SERVER_ERROR -} ProxyEvent; - -/* event can't be NONE when this callback is called */ -typedef void (*ProxyEventFunc)( void* opaque, int fd, ProxyEvent event ); - -extern void proxy_set_verbose(int mode); - - -typedef enum { - PROXY_OPTION_AUTH_USERNAME = 1, - PROXY_OPTION_AUTH_PASSWORD, - - PROXY_OPTION_HTTP_NOCACHE = 100, - PROXY_OPTION_HTTP_KEEPALIVE, - PROXY_OPTION_HTTP_USER_AGENT, - - PROXY_OPTION_MAX - -} ProxyOptionType; - - -typedef struct { - ProxyOptionType type; - const char* string; - int string_len; -} ProxyOption; - - -/* add a new proxified socket connection to the manager's list. the event function - * will be called when the connection is established or refused. - * - * only IPv4 is supported at the moment, since our slirp code cannot handle IPv6 - * - * returns 0 on success, or -1 if there is no proxy service for this type of connection - */ -extern int proxy_manager_add( SockAddress* address, - SocketType sock_type, - ProxyEventFunc ev_func, - void* ev_opaque ); - -/* remove an on-going proxified socket connection from the manager's list. - * this is only necessary when the socket connection must be canceled before - * the connection accept/refusal occured - */ -extern void proxy_manager_del( void* ev_opaque ); - -/* this function is called to update the select file descriptor sets - * with those of the proxified connection sockets that are currently managed */ -extern void proxy_manager_select_fill( int *pcount, - fd_set* read_fds, - fd_set* write_fds, - fd_set* err_fds); - -/* this function is called to act on proxified connection sockets when network events arrive */ -extern void proxy_manager_poll( fd_set* read_fds, - fd_set* write_fds, - fd_set* err_fds ); - -#endif /* END */ diff --git a/proxy/proxy_http.c b/proxy/proxy_http.c deleted file mode 100644 index f753587..0000000 --- a/proxy/proxy_http.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "proxy_int.h" -#include "proxy_http_int.h" -#include "qemu-common.h" -#include -#include -#include - -#define HTTP_VERSION "1.1" - -static void -http_service_free( HttpService* service ) -{ - PROXY_LOG("%s", __FUNCTION__); - if (service->footer != service->footer0) - qemu_free(service->footer); - qemu_free(service); -} - - -static ProxyConnection* -http_service_connect( HttpService* service, - SocketType sock_type, - SockAddress* address ) -{ - /* the HTTP proxy can only handle TCP connections */ - if (sock_type != SOCKET_STREAM) - return NULL; - - /* if the client tries to directly connect to the proxy, let it do so */ - if (sock_address_equal( address, &service->server_addr )) - return NULL; - - PROXY_LOG("%s: trying to connect to %s", - __FUNCTION__, sock_address_to_string(address)); - - if (sock_address_get_port(address) == 80) { - /* use the rewriter for HTTP */ - PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); - return http_rewriter_connect(service, address); - } else { - PROXY_LOG("%s: using HTTP rewriter", __FUNCTION__); - return http_connector_connect(service, address); - } -} - - -int -proxy_http_setup( const char* servername, - int servernamelen, - int serverport, - int num_options, - const ProxyOption* options ) -{ - HttpService* service; - SockAddress server_addr; - const ProxyOption* opt_nocache = NULL; - const ProxyOption* opt_keepalive = NULL; - const ProxyOption* opt_auth_user = NULL; - const ProxyOption* opt_auth_pass = NULL; - const ProxyOption* opt_user_agent = NULL; - - if (servernamelen < 0) - servernamelen = strlen(servername); - - PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d", - __FUNCTION__, servernamelen, servername, serverport ); - - /* resolve server address */ - if (proxy_resolve_server(&server_addr, servername, - servernamelen, serverport) < 0) - { - return -1; - } - - /* create service object */ - service = qemu_mallocz(sizeof(*service)); - if (service == NULL) { - PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__); - return -1; - } - - service->server_addr = server_addr; - - /* parse options */ - { - const ProxyOption* opt = options; - const ProxyOption* end = opt + num_options; - - for ( ; opt < end; opt++ ) { - switch (opt->type) { - case PROXY_OPTION_HTTP_NOCACHE: opt_nocache = opt; break; - case PROXY_OPTION_HTTP_KEEPALIVE: opt_keepalive = opt; break; - case PROXY_OPTION_AUTH_USERNAME: opt_auth_user = opt; break; - case PROXY_OPTION_AUTH_PASSWORD: opt_auth_pass = opt; break; - case PROXY_OPTION_HTTP_USER_AGENT: opt_user_agent = opt; break; - default: ; - } - } - } - - /* prepare footer */ - { - int wlen; - char* p = service->footer0; - char* end = p + sizeof(service->footer0); - - /* no-cache */ - if (opt_nocache) { - p += snprintf(p, end-p, "Pragma: no-cache\r\nCache-Control: no-cache\r\n"); - if (p >= end) goto FooterOverflow; - } - /* keep-alive */ - if (opt_keepalive) { - p += snprintf(p, end-p, "Connection: Keep-Alive\r\nProxy-Connection: Keep-Alive\r\n"); - if (p >= end) goto FooterOverflow; - } - /* authentication */ - if (opt_auth_user && opt_auth_pass) { - char user_pass[256]; - char encoded[512]; - int uplen; - - uplen = snprintf( user_pass, sizeof(user_pass), "%.*s:%.*s", - opt_auth_user->string_len, opt_auth_user->string, - opt_auth_pass->string_len, opt_auth_pass->string ); - - if (uplen >= sizeof(user_pass)) goto FooterOverflow; - - wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded)); - if (wlen < 0) { - PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass); - goto FooterOverflow; - } - - p += snprintf(p, end-p, "Proxy-authorization: Basic %.*s\r\n", wlen, encoded); - if (p >= end) goto FooterOverflow; - } - /* user agent */ - if (opt_user_agent) { - p += snprintf(p, end-p, "User-Agent: %.*s\r\n", - opt_user_agent->string_len, - opt_user_agent->string); - if (p >= end) goto FooterOverflow; - } - - p += snprintf(p, end-p, "\r\n"); - - if (p >= end) { - FooterOverflow: - PROXY_LOG( "%s: buffer overflow when creating connection footer", - __FUNCTION__); - http_service_free(service); - return -1; - } - - service->footer = service->footer0; - service->footer_len = (p - service->footer); - } - - PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'", - __FUNCTION__, service->footer_len, - service->footer_len, service->footer ); - - service->root->opaque = service; - service->root->serv_free = (ProxyServiceFreeFunc) http_service_free; - service->root->serv_connect = (ProxyServiceConnectFunc) http_service_connect; - - if (proxy_manager_add_service( service->root ) < 0) { - PROXY_LOG("%s: could not register service ?", __FUNCTION__); - http_service_free(service); - return -1; - } - return 0; -} - diff --git a/proxy/proxy_http.h b/proxy/proxy_http.h deleted file mode 100644 index a2e2917..0000000 --- a/proxy/proxy_http.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _PROXY_HTTP_H -#define _PROXY_HTTP_H - -#include "proxy_common.h" - -extern int -proxy_http_setup( const char* servername, - int servernamelen, - int serverport, - int num_options, - const ProxyOption* options ); - -#endif /* END */ diff --git a/proxy/proxy_http_connector.c b/proxy/proxy_http_connector.c deleted file mode 100644 index 6f03d9b..0000000 --- a/proxy/proxy_http_connector.c +++ /dev/null @@ -1,203 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "proxy_http_int.h" -#include -#include -#include -#include "qemu-common.h" - -/* A HttpConnector implements a non-HTTP proxied connection - * through the CONNECT method. Many firewalls are configured - * to reject these for port 80, so these connections should - * use a HttpRewriter instead. - */ - -typedef enum { - STATE_NONE = 0, - STATE_CONNECTING, /* connecting to the server */ - STATE_SEND_HEADER, /* connected, sending header to the server */ - STATE_RECEIVE_ANSWER_LINE1, - STATE_RECEIVE_ANSWER_LINE2 /* connected, reading server's answer */ -} ConnectorState; - -typedef struct Connection { - ProxyConnection root[1]; - ConnectorState state; -} Connection; - - -static void -connection_free( ProxyConnection* root ) -{ - proxy_connection_done(root); - qemu_free(root); -} - - - -#define HTTP_VERSION "1.1" - -static int -connection_init( Connection* conn ) -{ - HttpService* service = (HttpService*) conn->root->service; - ProxyConnection* root = conn->root; - stralloc_t* str = root->str; - - proxy_connection_rewind(root); - stralloc_add_format(str, "CONNECT %s HTTP/" HTTP_VERSION "\r\n", - sock_address_to_string(&root->address)); - - stralloc_add_bytes(str, service->footer, service->footer_len); - - if (!socket_connect( root->socket, &service->server_addr )) { - /* immediate connection ?? */ - conn->state = STATE_SEND_HEADER; - PROXY_LOG("%s: immediate connection", root->name); - } - else { - if (errno == EINPROGRESS || errno == EWOULDBLOCK) { - conn->state = STATE_CONNECTING; - PROXY_LOG("%s: connecting", root->name); - } - else { - PROXY_LOG("%s: cannot connect to proxy: %s", root->name, errno_str); - return -1; - } - } - return 0; -} - - -static void -connection_select( ProxyConnection* root, - ProxySelect* sel ) -{ - unsigned flags; - Connection* conn = (Connection*)root; - - switch (conn->state) { - case STATE_RECEIVE_ANSWER_LINE1: - case STATE_RECEIVE_ANSWER_LINE2: - flags = PROXY_SELECT_READ; - break; - - case STATE_CONNECTING: - case STATE_SEND_HEADER: - flags = PROXY_SELECT_WRITE; - break; - - default: - flags = 0; - }; - proxy_select_set(sel, root->socket, flags); -} - -static void -connection_poll( ProxyConnection* root, - ProxySelect* sel ) -{ - DataStatus ret = DATA_NEED_MORE; - Connection* conn = (Connection*)root; - int fd = root->socket; - - if (!proxy_select_poll(sel, fd)) - return; - - switch (conn->state) - { - case STATE_CONNECTING: - PROXY_LOG("%s: connected to http proxy, sending header", root->name); - conn->state = STATE_SEND_HEADER; - break; - - case STATE_SEND_HEADER: - ret = proxy_connection_send(root, fd); - if (ret == DATA_COMPLETED) { - conn->state = STATE_RECEIVE_ANSWER_LINE1; - PROXY_LOG("%s: header sent, receiving first answer line", root->name); - } - break; - - case STATE_RECEIVE_ANSWER_LINE1: - case STATE_RECEIVE_ANSWER_LINE2: - ret = proxy_connection_receive_line(root, root->socket); - if (ret == DATA_COMPLETED) { - if (conn->state == STATE_RECEIVE_ANSWER_LINE1) { - int http1, http2, codenum; - const char* line = root->str->s; - - if ( sscanf(line, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) { - PROXY_LOG( "%s: invalid answer from proxy: '%s'", - root->name, line ); - ret = DATA_ERROR; - break; - } - - /* success is 2xx */ - if (codenum/2 != 100) { - PROXY_LOG( "%s: connection refused, error=%d", - root->name, codenum ); - proxy_connection_free( root, 0, PROXY_EVENT_CONNECTION_REFUSED ); - return; - } - PROXY_LOG("%s: receiving second answer line", root->name); - conn->state = STATE_RECEIVE_ANSWER_LINE2; - proxy_connection_rewind(root); - } else { - /* ok, we're connected */ - PROXY_LOG("%s: connection succeeded", root->name); - proxy_connection_free( root, 1, PROXY_EVENT_CONNECTED ); - } - } - break; - - default: - PROXY_LOG("%s: invalid state for read event: %d", root->name, conn->state); - } - - if (ret == DATA_ERROR) { - proxy_connection_free( root, 0, PROXY_EVENT_SERVER_ERROR ); - } -} - - - -ProxyConnection* -http_connector_connect( HttpService* service, - SockAddress* address ) -{ - Connection* conn; - int s; - - s = socket_create_inet( SOCKET_STREAM ); - if (s < 0) - return NULL; - - conn = qemu_mallocz(sizeof(*conn)); - if (conn == NULL) { - socket_close(s); - return NULL; - } - - proxy_connection_init( conn->root, s, address, service->root, - connection_free, - connection_select, - connection_poll ); - - if ( connection_init( conn ) < 0 ) { - connection_free( conn->root ); - return NULL; - } - - return conn->root; -} diff --git a/proxy/proxy_http_int.h b/proxy/proxy_http_int.h deleted file mode 100644 index 6daa9cb..0000000 --- a/proxy/proxy_http_int.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _PROXY_HTTP_INT_H -#define _PROXY_HTTP_INT_H - -#include "proxy_http.h" -#include "proxy_int.h" - -/* the HttpService object */ -typedef struct HttpService { - ProxyService root[1]; - SockAddress server_addr; /* server address and port */ - char* footer; /* the footer contains the static parts of the */ - int footer_len; /* connection header, we generate it only once */ - char footer0[512]; -} HttpService; - -/* create a CONNECT connection (for port != 80) */ -extern ProxyConnection* http_connector_connect( - HttpService* service, - SockAddress* address ); - -/* create a HTTP rewriting connection (for port == 80) */ -extern ProxyConnection* http_rewriter_connect( - HttpService* service, - SockAddress* address ); - - -#endif /* _PROXY_HTTP_INT_H */ diff --git a/proxy/proxy_http_rewriter.c b/proxy/proxy_http_rewriter.c deleted file mode 100644 index 812bf9c..0000000 --- a/proxy/proxy_http_rewriter.c +++ /dev/null @@ -1,1125 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#include "proxy_http_int.h" -#include -#include -#include "qemu-common.h" -#include "android/utils/system.h" /* strsep */ - -/* this implements a transparent HTTP rewriting proxy - * - * this is needed because the HTTP spec mandates that - * any query made to a proxy uses an absolute URI as - * in: - * - * GET http://www.example.com/index.html HTTP/1.1 - * - * while the Android browser will think it's talking to - * a normal web server and will issue a: - * - * GET /index.html HTTP/1.1 - * Host: www.example.com - * - * what we do here is thus the following: - * - * - read the request header - * - rewrite the request's URI to use absolute URI - * - send the rewritten header to the proxy - * - then read the rest of the request, and tunnel it to the - * proxy as well - * - read the answer as-is and send it back to the system - * - * this sounds all easy, but the rules for computing the - * sizes of HTTP Message Bodies makes the implementation - * a *bit* funky. - */ - -/* define D_ACTIVE to 1 to dump additionnal debugging - * info when -debug-proxy is used. These are only needed - * when debugging the proxy code. - */ -#define D_ACTIVE 1 - -#if D_ACTIVE -# define D(...) PROXY_LOG(__VA_ARGS__) -#else -# define D(...) ((void)0) -#endif - - -/** ************************************************************* - ** - ** HTTP HEADERS - ** - **/ - -typedef struct HttpHeader { - struct HttpHeader* next; - const char* key; - const char* value; -} HttpHeader; - -static void -http_header_free( HttpHeader* h ) -{ - if (h) { - qemu_free((char*)h->value); - qemu_free(h); - } -} - -static int -http_header_append( HttpHeader* h, const char* value ) -{ - int old = strlen(h->value); - int new = strlen(value); - char* s = realloc((char*)h->value, old+new+1); - if (s == NULL) - return -1; - memcpy(s + old, value, new+1); - h->value = (const char*)s; - return 0; -} - -static HttpHeader* -http_header_alloc( const char* key, const char* value ) -{ - int len = strlen(key)+1; - HttpHeader* h = malloc(sizeof(*h) + len+1); - if (h) { - h->next = NULL; - h->key = (const char*)(h+1); - memcpy( (char*)h->key, key, len ); - h->value = qemu_strdup(value); - } - return h; -} - -typedef struct { - HttpHeader* first; - HttpHeader* last; -} HttpHeaderList; - -static void -http_header_list_init( HttpHeaderList* l ) -{ - l->first = l->last = NULL; -} - -static void -http_header_list_done( HttpHeaderList* l ) -{ - while (l->first) { - HttpHeader* h = l->first; - l->first = h->next; - http_header_free(h); - } - l->last = NULL; -} - -static void -http_header_list_add( HttpHeaderList* l, - HttpHeader* h ) -{ - if (!l->first) { - l->first = h; - } else { - l->last->next = h; - } - h->next = NULL; - l->last = h; -} - -static const char* -http_header_list_find( HttpHeaderList* l, - const char* key ) -{ - HttpHeader* h; - for (h = l->first; h; h = h->next) - if (!strcasecmp(h->key, key)) - return h->value; - - return NULL; -} - -/** ************************************************************* - ** - ** HTTP REQUEST AND REPLY - ** - **/ - -typedef enum { - HTTP_REQUEST_UNSUPPORTED = 0, - HTTP_REQUEST_GET, - HTTP_REQUEST_HEAD, - HTTP_REQUEST_POST, - HTTP_REQUEST_PUT, - HTTP_REQUEST_DELETE, -} HttpRequestType; - -typedef struct { - HttpRequestType req_type; - char* req_method; - char* req_uri; - char* req_version; - char* rep_version; - int rep_code; - char* rep_readable; - HttpHeaderList headers[1]; -} HttpRequest; - - -static HttpRequest* -http_request_alloc( const char* method, - const char* uri, - const char* version ) -{ - HttpRequest* r = malloc(sizeof(*r)); - - r->req_method = qemu_strdup(method); - r->req_uri = qemu_strdup(uri); - r->req_version = qemu_strdup(version); - r->rep_version = NULL; - r->rep_code = -1; - r->rep_readable = NULL; - - if (!strcmp(method,"GET")) { - r->req_type = HTTP_REQUEST_GET; - } else if (!strcmp(method,"POST")) { - r->req_type = HTTP_REQUEST_POST; - } else if (!strcmp(method,"HEAD")) { - r->req_type = HTTP_REQUEST_HEAD; - } else if (!strcmp(method,"PUT")) { - r->req_type = HTTP_REQUEST_PUT; - } else if (!strcmp(method,"DELETE")) { - r->req_type = HTTP_REQUEST_DELETE; - } else - r->req_type = HTTP_REQUEST_UNSUPPORTED; - - http_header_list_init(r->headers); - return r; -} - -static void -http_request_replace_uri( HttpRequest* r, - const char* uri ) -{ - const char* old = r->req_uri; - r->req_uri = qemu_strdup(uri); - qemu_free((char*)old); -} - -static void -http_request_free( HttpRequest* r ) -{ - if (r) { - http_header_list_done(r->headers); - - qemu_free(r->req_method); - qemu_free(r->req_uri); - qemu_free(r->req_version); - qemu_free(r->rep_version); - qemu_free(r->rep_readable); - qemu_free(r); - } -} - -static char* -http_request_find_header( HttpRequest* r, - const char* key ) -{ - return (char*)http_header_list_find(r->headers, key); -} - - -static int -http_request_add_header( HttpRequest* r, - const char* key, - const char* value ) -{ - HttpHeader* h = http_header_alloc(key,value); - if (h) { - http_header_list_add(r->headers, h); - return 0; - } - return -1; -} - -static int -http_request_add_to_last_header( HttpRequest* r, - const char* line ) -{ - if (r->headers->last) { - return http_header_append( r->headers->last, line ); - } else { - return -1; - } -} - -static int -http_request_set_reply( HttpRequest* r, - const char* version, - const char* code, - const char* readable ) -{ - if (strcmp(version,"HTTP/1.0") && strcmp(version,"HTTP/1.1")) { - PROXY_LOG("%s: bad reply protocol: %s", __FUNCTION__, version); - return -1; - } - r->rep_code = atoi(code); - if (r->rep_code == 0) { - PROXY_LOG("%s: bad reply code: %d", __FUNCTION__, code); - return -1; - } - - r->rep_version = qemu_strdup(version); - r->rep_readable = qemu_strdup(readable); - - /* reset the list of headers */ - http_header_list_done(r->headers); - return 0; -} - -/** ************************************************************* - ** - ** REWRITER CONNECTION - ** - **/ - -typedef enum { - STATE_CONNECTING = 0, - STATE_CREATE_SOCKET_PAIR, - STATE_REQUEST_FIRST_LINE, - STATE_REQUEST_HEADERS, - STATE_REQUEST_SEND, - STATE_REQUEST_BODY, - STATE_REPLY_FIRST_LINE, - STATE_REPLY_HEADERS, - STATE_REPLY_SEND, - STATE_REPLY_BODY, -} ConnectionState; - -/* root->socket is connected to the proxy server. while - * slirp_fd is connected to the slirp code through a - * socket_pair() we created for this specific purpose. - */ - -typedef enum { - BODY_NONE = 0, - BODY_KNOWN_LENGTH, - BODY_UNTIL_CLOSE, - BODY_CHUNKED, - BODY_MODE_MAX -} BodyMode; - -static const char* const body_mode_str[BODY_MODE_MAX] = { - "NONE", "KNOWN_LENGTH", "UNTIL_CLOSE", "CHUNKED" -}; - -typedef struct { - ProxyConnection root[1]; - int slirp_fd; - ConnectionState state; - HttpRequest* request; - BodyMode body_mode; - int64_t body_length; - int64_t body_total; - int64_t body_sent; - int64_t chunk_length; - int64_t chunk_total; - char body_has_data; - char body_is_full; - char body_is_closed; - char parse_chunk_header; - char parse_chunk_trailer; -} RewriteConnection; - - -static void -rewrite_connection_free( ProxyConnection* root ) -{ - RewriteConnection* conn = (RewriteConnection*)root; - - if (conn->slirp_fd >= 0) { - socket_close(conn->slirp_fd); - conn->slirp_fd = -1; - } - http_request_free(conn->request); - proxy_connection_done(root); - qemu_free(conn); -} - - -static int -rewrite_connection_init( RewriteConnection* conn ) -{ - HttpService* service = (HttpService*) conn->root->service; - ProxyConnection* root = conn->root; - - conn->slirp_fd = -1; - conn->state = STATE_CONNECTING; - - if (socket_connect( root->socket, &service->server_addr ) < 0) { - if (errno == EINPROGRESS || errno == EWOULDBLOCK) { - PROXY_LOG("%s: connecting", conn->root->name); - } - else { - PROXY_LOG("%s: cannot connect to proxy: %s", root->name, errno_str); - return -1; - } - } - else { - PROXY_LOG("%s: immediate connection", root->name); - conn->state = STATE_CREATE_SOCKET_PAIR; - } - return 0; -} - -static int -rewrite_connection_create_sockets( RewriteConnection* conn ) -{ - /* immediate connection to the proxy. now create a socket - * pair and send a 'success' event to slirp */ - int slirp_1; - ProxyConnection* root = conn->root; - - if (socket_pair( &slirp_1, &conn->slirp_fd ) < 0) { - PROXY_LOG("%s: coult not create socket pair: %s", - root->name, errno_str); - return -1; - } - - root->ev_func( root->ev_opaque, slirp_1, PROXY_EVENT_CONNECTED ); - conn->state = STATE_REQUEST_FIRST_LINE; - return 0; -} - - -/* read the first line of a given HTTP request. returns -1/0/+1 */ -static DataStatus -rewrite_connection_read_request( RewriteConnection* conn ) -{ - ProxyConnection* root = conn->root; - DataStatus ret; - - ret = proxy_connection_receive_line(root, conn->slirp_fd); - if (ret == DATA_COMPLETED) { - /* now parse the first line to see if we can handle it */ - char* line = root->str->s; - char* method; - char* uri; - char* version; - char* p = line; - - method = strsep(&p, " "); - if (p == NULL) { - PROXY_LOG("%s: can't parse method in '%'", - root->name, line); - return DATA_ERROR; - } - uri = strsep(&p, " "); - if (p == NULL) { - PROXY_LOG( "%s: can't parse URI in '%s'", - root->name, line); - return DATA_ERROR; - } - version = strsep(&p, " "); - if (p != NULL) { - PROXY_LOG( "%s: extra data after version in '%s'", - root->name, line); - return DATA_ERROR; - } - if (conn->request) - http_request_free(conn->request); - - conn->request = http_request_alloc( method, uri, version ); - if (!conn->request) - return DATA_ERROR; - - proxy_connection_rewind(root); - } - return ret; -} - - -static DataStatus -rewrite_connection_read_reply( RewriteConnection* conn ) -{ - ProxyConnection* root = conn->root; - DataStatus ret; - - ret = proxy_connection_receive_line( root, root->socket ); - if (ret == DATA_COMPLETED) { - HttpRequest* request = conn->request; - - char* line = stralloc_cstr( root->str ); - char* p = line; - char* protocol; - char* number; - char* readable; - - protocol = strsep(&p, " "); - if (p == NULL) { - PROXY_LOG("%s: can't parse response protocol: '%s'", - root->name, line); - return DATA_ERROR; - } - number = strsep(&p, " "); - if (p == NULL) { - PROXY_LOG("%s: can't parse response number: '%s'", - root->name, line); - return DATA_ERROR; - } - readable = p; - - if (http_request_set_reply(request, protocol, number, readable) < 0) - return DATA_ERROR; - - proxy_connection_rewind(root); - } - return ret; -} - - -static DataStatus -rewrite_connection_read_headers( RewriteConnection* conn, - int fd ) -{ - int ret; - ProxyConnection* root = conn->root; - - for (;;) { - char* line; - stralloc_t* str = root->str; - - ret = proxy_connection_receive_line(root, fd); - if (ret != DATA_COMPLETED) - break; - - str->n = 0; - line = str->s; - - if (line[0] == 0) { - /* an empty line means the end of headers */ - ret = 1; - break; - } - - /* it this a continuation ? */ - if (line[0] == ' ' || line[0] == '\t') { - ret = http_request_add_to_last_header( conn->request, line ); - } - else { - char* key; - char* value; - - value = line; - key = strsep(&value, ":"); - if (value == NULL) { - PROXY_LOG("%s: can't parse header '%s'", root->name, line); - ret = -1; - break; - } - value += strspn(value, " "); - if (http_request_add_header(conn->request, key, value) < 0) - ret = -1; - } - if (ret == DATA_ERROR) - break; - } - return ret; -} - -static int -rewrite_connection_rewrite_request( RewriteConnection* conn ) -{ - ProxyConnection* root = conn->root; - HttpService* service = (HttpService*) root->service; - HttpRequest* r = conn->request; - stralloc_t* str = root->str; - HttpHeader* h; - - proxy_connection_rewind(conn->root); - - /* only rewrite the URI if it is not absolute */ - if (r->req_uri[0] == '/') { - char* host = http_request_find_header(r, "Host"); - if (host == NULL) { - PROXY_LOG("%s: uh oh, not Host: in request ?", root->name); - } else { - /* now create new URI */ - stralloc_add_str(str, "http://"); - stralloc_add_str(str, host); - stralloc_add_str(str, r->req_uri); - http_request_replace_uri(r, stralloc_cstr(str)); - proxy_connection_rewind(root); - } - } - - stralloc_format( str, "%s %s %s\r\n", r->req_method, r->req_uri, r->req_version ); - for (h = r->headers->first; h; h = h->next) { - stralloc_add_format( str, "%s: %s\r\n", h->key, h->value ); - } - /* add the service's footer - includes final \r\n */ - stralloc_add_bytes( str, service->footer, service->footer_len ); - - return 0; -} - -static int -rewrite_connection_rewrite_reply( RewriteConnection* conn ) -{ - HttpRequest* r = conn->request; - ProxyConnection* root = conn->root; - stralloc_t* str = root->str; - HttpHeader* h; - - proxy_connection_rewind(root); - stralloc_format(str, "%s %d %s\r\n", r->rep_version, r->rep_code, r->rep_readable); - for (h = r->headers->first; h; h = h->next) { - stralloc_add_format(str, "%s: %s\r\n", h->key, h->value); - } - stralloc_add_str(str, "\r\n"); - - return 0; -} - - -static int -rewrite_connection_get_body_length( RewriteConnection* conn, - int is_request ) -{ - HttpRequest* r = conn->request; - ProxyConnection* root = conn->root; - char* content_length; - char* transfer_encoding; - - conn->body_mode = BODY_NONE; - conn->body_length = 0; - conn->body_total = 0; - conn->body_sent = 0; - conn->body_is_closed = 0; - conn->body_is_full = 0; - conn->body_has_data = 0; - - proxy_connection_rewind(root); - - if (is_request) { - /* only POST and PUT should have a body */ - if (r->req_type != HTTP_REQUEST_POST && - r->req_type != HTTP_REQUEST_PUT) - { - return 0; - } - } else { - /* HTTP 1.1 Section 4.3 Message Body states that HEAD requests must not have - * a message body, as well as any 1xx, 204 and 304 replies */ - if (r->req_type == HTTP_REQUEST_HEAD || r->rep_code/100 == 1 || - r->rep_code == 204 || r->rep_code == 304) - return 0; - } - - content_length = http_request_find_header(r, "Content-Length"); - if (content_length != NULL) { - char* end; - int64_t body_len = strtoll( content_length, &end, 10 ); - if (*end != '\0' || *content_length == '\0' || body_len < 0) { - PROXY_LOG("%s: bad content length: %s", root->name, content_length); - return DATA_ERROR; - } - if (body_len > 0) { - conn->body_mode = BODY_KNOWN_LENGTH; - conn->body_length = body_len; - } - } else { - char* connection = http_request_find_header(r, "Proxy-Connection"); - - if (!connection) - connection = http_request_find_header(r, "Connection"); - - if (!connection || strcasecmp(connection, "Close")) { - /* hum, we can't support this at all */ - PROXY_LOG("%s: can't determine content length, and client wants" - " to keep connection opened", - root->name); - return -1; - } - /* a negative value means that the data ends when the client - * disconnects the connection. - */ - conn->body_mode = BODY_UNTIL_CLOSE; - } - transfer_encoding = http_request_find_header(r, "Transfer-Encoding"); - if (transfer_encoding && !strcasecmp(transfer_encoding, "Chunked")) { - conn->body_mode = BODY_CHUNKED; - conn->parse_chunk_header = 0; - conn->parse_chunk_trailer = 0; - conn->chunk_length = -1; - conn->chunk_total = 0; - } - D("%s: body_length=%lld body_mode=%s", - root->name, conn->body_length, - body_mode_str[conn->body_mode]); - - proxy_connection_rewind(root); - return 0; -} - -#define MAX_BODY_BUFFER 65536 - -static DataStatus -rewrite_connection_read_body( RewriteConnection* conn, int fd ) -{ - ProxyConnection* root = conn->root; - stralloc_t* str = root->str; - int wanted = 0, current, avail; - DataStatus ret; - - if (conn->body_is_closed) { - return DATA_NEED_MORE; - } - - /* first, determine how many bytes we want to read. */ - switch (conn->body_mode) { - case BODY_NONE: - D("%s: INTERNAL ERROR: SHOULDN'T BE THERE", root->name); - return DATA_COMPLETED; - - case BODY_KNOWN_LENGTH: - { - if (conn->body_length == 0) - return DATA_COMPLETED; - - if (conn->body_length > MAX_BODY_BUFFER) - wanted = MAX_BODY_BUFFER; - else - wanted = (int)conn->body_length; - } - break; - - case BODY_UNTIL_CLOSE: - wanted = MAX_BODY_BUFFER; - break; - - case BODY_CHUNKED: - if (conn->chunk_length < 0) { - /* chunk_length < 0 means we need to read a chunk header */ - /* ensure that 'str' is flushed before doing this */ - if (!conn->parse_chunk_header) { - if (conn->body_has_data) - return DATA_NEED_MORE; - D("%s: waiting chunk header", root->name); - conn->parse_chunk_header = 1; - } - ret = proxy_connection_receive_line(root, fd); - if (ret == DATA_COMPLETED) { - char* line = str->s; - char* end; - long long length; - - length = strtoll(line, &end, 16); - if (line[0] == ' ' || (end[0] != '\0' && end[0] != ';')) { - PROXY_LOG("%s: invalid chunk header: %s", - root->name, line); - return DATA_ERROR; - } - if (length < 0) { - PROXY_LOG("%s: invalid chunk length %lld", - root->name, length); - return DATA_ERROR; - } - conn->chunk_length = length; - conn->chunk_total = 0; - if (length == 0) { - /* the last chunk, no we need to add the trailer */ - conn->parse_chunk_trailer = 0; - } - conn->parse_chunk_header = 0; - } - } - - if (conn->chunk_length == 0) { - /* chunk_length == 0 means we're reading the chunk trailer */ - /* ensure that 'str' is flushed before reading the trailer */ - if (!conn->parse_chunk_trailer) { - if (conn->body_has_data) - return DATA_NEED_MORE; - conn->parse_chunk_trailer = 1; - } - ret = rewrite_connection_read_headers(conn, fd); - if (ret == DATA_COMPLETED) { - conn->body_is_closed = 1; - } - return ret; - } - - /* if we get here, body_length > 0 */ - if (conn->chunk_length > MAX_BODY_BUFFER) - wanted = MAX_BODY_BUFFER; - else - wanted = (int)conn->chunk_length; - break; - - default: - ; - } - - /* we don't want more than MAX_BODY_BUFFER bytes in the - * buffer we used to pass the body */ - current = str->n; - avail = MAX_BODY_BUFFER - current; - if (avail <= 0) { - /* wait for some flush */ - conn->body_is_full = 1; - D("%s: waiting to flush %d bytes", - root->name, current); - return DATA_NEED_MORE; - } - - if (wanted > avail) - wanted = avail; - - ret = proxy_connection_receive(root, fd, wanted); - conn->body_has_data = (str->n > 0); - conn->body_is_full = (str->n == MAX_BODY_BUFFER); - - if (ret == DATA_ERROR) { - if (conn->body_mode == BODY_UNTIL_CLOSE) { - /* a disconnection here is normal and signals the - * end of the body */ - conn->body_total += root->str_recv; - D("%s: body completed by close (%lld bytes)", - root->name, conn->body_total); - conn->body_is_closed = 1; - ret = DATA_COMPLETED; - } - } else { - avail = root->str_recv; - ret = DATA_NEED_MORE; /* we're not really done yet */ - - switch (conn->body_mode) { - case BODY_CHUNKED: - conn->chunk_total += avail; - conn->chunk_length -= avail; - - if (conn->chunk_length == 0) { - D("%s: chunk completed (%lld bytes)", - root->name, conn->chunk_length); - conn->body_total += conn->chunk_total; - conn->chunk_total = 0; - conn->chunk_length = -1; - } - break; - - case BODY_KNOWN_LENGTH: - conn->body_length -= avail; - conn->body_total += avail; - - if (conn->body_length == 0) { - D("%s: body completed (%lld bytes)", - root->name, conn->body_total); - conn->body_is_closed = 1; - ret = DATA_COMPLETED; - } - break; - - case BODY_UNTIL_CLOSE: - conn->body_total += avail; - break; - - default: - ; - } - } - return ret; -} - -static DataStatus -rewrite_connection_send_body( RewriteConnection* conn, int fd ) -{ - ProxyConnection* root = conn->root; - stralloc_t* str = root->str; - DataStatus ret = DATA_NEED_MORE; - - if (conn->body_has_data) { - ret = proxy_connection_send(root, fd); - if (ret != DATA_ERROR) { - int pos = root->str_pos; - - memmove(str->s, str->s+pos, str->n-pos); - str->n -= pos; - root->str_pos = 0; - conn->body_is_full = (str->n == MAX_BODY_BUFFER); - conn->body_has_data = (str->n > 0); - conn->body_sent += root->str_sent; - - /* ensure that we return DATA_COMPLETED only when - * we have sent everything, and there is no more - * body pieces to read */ - if (ret == DATA_COMPLETED) { - if (!conn->body_is_closed || conn->body_has_data) - ret = DATA_NEED_MORE; - else { - D("%s: sent all body (%lld bytes)", - root->name, conn->body_sent); - } - } - D("%s: sent closed=%d data=%d n=%d ret=%d", - root->name, conn->body_is_closed, - conn->body_has_data, str->n, - ret); - } - } - return ret; -} - - -static void -rewrite_connection_select( ProxyConnection* root, - ProxySelect* sel ) -{ - RewriteConnection* conn = (RewriteConnection*)root; - int slirp = conn->slirp_fd; - int proxy = root->socket; - - switch (conn->state) { - case STATE_CONNECTING: - case STATE_CREATE_SOCKET_PAIR: - /* try to connect to the proxy server */ - proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); - break; - - case STATE_REQUEST_FIRST_LINE: - case STATE_REQUEST_HEADERS: - proxy_select_set( sel, slirp, PROXY_SELECT_READ ); - break; - - case STATE_REQUEST_SEND: - proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); - break; - - case STATE_REQUEST_BODY: - if (!conn->body_is_closed && !conn->body_is_full) - proxy_select_set( sel, slirp, PROXY_SELECT_READ ); - - if (conn->body_has_data) - proxy_select_set( sel, proxy, PROXY_SELECT_WRITE ); - break; - - case STATE_REPLY_FIRST_LINE: - case STATE_REPLY_HEADERS: - proxy_select_set( sel, proxy, PROXY_SELECT_READ ); - break; - - case STATE_REPLY_SEND: - proxy_select_set( sel, slirp, PROXY_SELECT_WRITE ); - break; - - case STATE_REPLY_BODY: - if (conn->body_has_data) - proxy_select_set( sel, slirp, PROXY_SELECT_WRITE ); - - if (!conn->body_is_closed && !conn->body_is_full) - proxy_select_set( sel, proxy, PROXY_SELECT_READ ); - break; - default: - ; - }; -} - -static void -rewrite_connection_poll( ProxyConnection* root, - ProxySelect* sel ) -{ - RewriteConnection* conn = (RewriteConnection*)root; - - int slirp = conn->slirp_fd; - int proxy = root->socket; - int has_slirp = proxy_select_poll(sel, slirp); - int has_proxy = proxy_select_poll(sel, proxy); - DataStatus ret = DATA_NEED_MORE; - - switch (conn->state) { - case STATE_CONNECTING: - if (has_proxy) { - PROXY_LOG("%s: connected to proxy", root->name); - conn->state = STATE_CREATE_SOCKET_PAIR; - } - break; - - case STATE_CREATE_SOCKET_PAIR: - if (has_proxy) { - if (rewrite_connection_create_sockets(conn) < 0) { - ret = DATA_ERROR; - } else { - D("%s: socket pair created", root->name); - conn->state = STATE_REQUEST_FIRST_LINE; - } - } - break; - - case STATE_REQUEST_FIRST_LINE: - if (has_slirp) { - ret = rewrite_connection_read_request(conn); - if (ret == DATA_COMPLETED) { - PROXY_LOG("%s: request first line ok", root->name); - conn->state = STATE_REQUEST_HEADERS; - } - } - break; - - case STATE_REQUEST_HEADERS: - if (has_slirp) { - ret = rewrite_connection_read_headers(conn, slirp); - if (ret == DATA_COMPLETED) { - PROXY_LOG("%s: request headers ok", root->name); - if (rewrite_connection_rewrite_request(conn) < 0) - ret = DATA_ERROR; - else - conn->state = STATE_REQUEST_SEND; - } - } - break; - - case STATE_REQUEST_SEND: - if (has_proxy) { - ret = proxy_connection_send(root, proxy); - if (ret == DATA_COMPLETED) { - if (rewrite_connection_get_body_length(conn, 1) < 0) { - ret = DATA_ERROR; - } else if (conn->body_mode != BODY_NONE) { - PROXY_LOG("%s: request sent, waiting for body", - root->name); - conn->state = STATE_REQUEST_BODY; - } else { - PROXY_LOG("%s: request sent, waiting for reply", - root->name); - conn->state = STATE_REPLY_FIRST_LINE; - } - } - } - break; - - case STATE_REQUEST_BODY: - if (has_slirp) { - ret = rewrite_connection_read_body(conn, slirp); - } - if (ret != DATA_ERROR && has_proxy) { - ret = rewrite_connection_send_body(conn, proxy); - if (ret == DATA_COMPLETED) { - PROXY_LOG("%s: request body ok, waiting for reply", - root->name); - conn->state = STATE_REPLY_FIRST_LINE; - } - } - break; - - case STATE_REPLY_FIRST_LINE: - if (has_proxy) { - ret = rewrite_connection_read_reply(conn); - if (ret == DATA_COMPLETED) { - PROXY_LOG("%s: reply first line ok", root->name); - conn->state = STATE_REPLY_HEADERS; - } - } - break; - - case STATE_REPLY_HEADERS: - if (has_proxy) { - ret = rewrite_connection_read_headers(conn, proxy); - if (ret == DATA_COMPLETED) { - PROXY_LOG("%s: reply headers ok", root->name); - if (rewrite_connection_rewrite_reply(conn) < 0) - ret = DATA_ERROR; - else - conn->state = STATE_REPLY_SEND; - } - } - break; - - case STATE_REPLY_SEND: - if (has_slirp) { - ret = proxy_connection_send(conn->root, slirp); - if (ret == DATA_COMPLETED) { - if (rewrite_connection_get_body_length(conn, 0) < 0) { - ret = DATA_ERROR; - } else if (conn->body_mode != BODY_NONE) { - PROXY_LOG("%s: reply sent, waiting for body", - root->name); - conn->state = STATE_REPLY_BODY; - } else { - PROXY_LOG("%s: reply sent, looping to waiting request", - root->name); - conn->state = STATE_REQUEST_FIRST_LINE; - } - } - } - break; - - case STATE_REPLY_BODY: - if (has_proxy) { - ret = rewrite_connection_read_body(conn, proxy); - } - if (ret != DATA_ERROR && has_slirp) { - ret = rewrite_connection_send_body(conn, slirp); - if (ret == DATA_COMPLETED) { - if (conn->body_mode == BODY_UNTIL_CLOSE) { - PROXY_LOG("%s: closing connection", root->name); - ret = DATA_ERROR; - } else { - PROXY_LOG("%s: reply body ok, looping to waiting request", - root->name); - conn->state = STATE_REQUEST_FIRST_LINE; - } - } - } - break; - - default: - ; - } - if (ret == DATA_ERROR) - proxy_connection_free(root, 0, PROXY_EVENT_NONE); - - return; -} - - -ProxyConnection* -http_rewriter_connect( HttpService* service, - SockAddress* address ) -{ - RewriteConnection* conn; - int s; - - s = socket_create_inet( SOCKET_STREAM ); - if (s < 0) - return NULL; - - conn = qemu_mallocz(sizeof(*conn)); - if (conn == NULL) { - socket_close(s); - return NULL; - } - - proxy_connection_init( conn->root, s, address, service->root, - rewrite_connection_free, - rewrite_connection_select, - rewrite_connection_poll ); - - if ( rewrite_connection_init( conn ) < 0 ) { - rewrite_connection_free( conn->root ); - return NULL; - } - - return conn->root; -} diff --git a/proxy/proxy_int.h b/proxy/proxy_int.h deleted file mode 100644 index 739bb75..0000000 --- a/proxy/proxy_int.h +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright (C) 2007-2008 The Android Open Source Project -** -** This software is licensed under the terms of the GNU General Public -** License version 2, as published by the Free Software Foundation, and -** may be copied, distributed, and modified under those terms. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -*/ -#ifndef _PROXY_INT_H -#define _PROXY_INT_H - -#include "proxy_common.h" -#include "sockets.h" -#include "android/utils/stralloc.h" - -extern int proxy_log; - -extern void -proxy_LOG(const char* fmt, ...); - -#define PROXY_LOG(...) \ - do { if (proxy_log) proxy_LOG(__VA_ARGS__); } while (0) - - -/* ProxySelect is used to handle events */ - -enum { - PROXY_SELECT_READ = (1 << 0), - PROXY_SELECT_WRITE = (1 << 1), - PROXY_SELECT_ERROR = (1 << 2) -}; - -typedef struct { - int* pcount; - fd_set* reads; - fd_set* writes; - fd_set* errors; -} ProxySelect; - -extern void proxy_select_set( ProxySelect* sel, - int fd, - unsigned flags ); - -extern unsigned proxy_select_poll( ProxySelect* sel, int fd ); - - -/* sockets proxy manager internals */ - -typedef struct ProxyConnection ProxyConnection; -typedef struct ProxyService ProxyService; - -/* free a given proxified connection */ -typedef void (*ProxyConnectionFreeFunc) ( ProxyConnection* conn ); - -/* modify the ProxySelect to tell which events to listen to */ -typedef void (*ProxyConnectionSelectFunc) ( ProxyConnection* conn, - ProxySelect* sel ); - -/* action a proxy connection when select() returns certain events for its socket */ -typedef void (*ProxyConnectionPollFunc) ( ProxyConnection* conn, - ProxySelect* sel ); - - -/* root ProxyConnection object */ -struct ProxyConnection { - int socket; - SockAddress address; /* for debugging */ - ProxyConnection* next; - ProxyConnection* prev; - ProxyEventFunc ev_func; - void* ev_opaque; - ProxyService* service; - - /* the following is useful for all types of services */ - char name[64]; /* for debugging purposes */ - - stralloc_t str[1]; /* network buffer (dynamic) */ - int str_pos; /* see proxy_connection_send() */ - int str_sent; /* see proxy_connection_send() */ - int str_recv; /* see proxy_connection_receive() */ - - /* connection methods */ - ProxyConnectionFreeFunc conn_free; - ProxyConnectionSelectFunc conn_select; - ProxyConnectionPollFunc conn_poll; - - /* rest of data depend on exact implementation */ -}; - - - -extern void -proxy_connection_init( ProxyConnection* conn, - int socket, - SockAddress* address, - ProxyService* service, - ProxyConnectionFreeFunc conn_free, - ProxyConnectionSelectFunc conn_select, - ProxyConnectionPollFunc conn_poll ); - -extern void -proxy_connection_done( ProxyConnection* conn ); - -/* free the proxy connection object. this will also - * close the corresponding socket unless the - * 'keep_alive' flag is set to TRUE. - */ -extern void -proxy_connection_free( ProxyConnection* conn, - int keep_alive, - ProxyEvent event ); - -/* status of data transfer operations */ -typedef enum { - DATA_ERROR = -1, - DATA_NEED_MORE = 0, - DATA_COMPLETED = 1 -} DataStatus; - -/* try to send data from the connection's buffer to a socket. - * starting from offset conn->str_pos in the buffer - * - * returns DATA_COMPLETED if everything could be written - * returns DATA_ERROR for a socket disconnection or error - * returns DATA_NEED_MORE if all data could not be sent. - * - * on exit, conn->str_sent contains the number of bytes - * that were really sent. conn->str_pos will be incremented - * by conn->str_sent as well. - * - * note that in case of success (DATA_COMPLETED), this also - * performs a proxy_connection_rewind which sets conn->str_pos - * to 0. - */ -extern DataStatus -proxy_connection_send( ProxyConnection* conn, int fd ); - -/* try to read 'wanted' bytes into conn->str from a socket - * - * returns DATA_COMPLETED if all bytes could be read - * returns DATA_NEED_MORE if not all bytes could be read - * returns DATA_ERROR in case of socket disconnection or error - * - * on exit, the amount of data received is in conn->str_recv - */ -extern DataStatus -proxy_connection_receive( ProxyConnection* conn, int fd, int wanted ); - -/* tries to receive a line of text from the proxy. - * when an entire line is read, the trailing \r\n is stripped - * and replaced by a terminating zero. str->n will be the - * lenght of the line, exclusing the terminating zero. - * returns 1 when a line has been received - * returns 0 if there is still some data to receive - * returns -1 in case of error - */ -extern DataStatus -proxy_connection_receive_line( ProxyConnection* conn, int fd ); - -/* rewind the string buffer for a new operation */ -extern void -proxy_connection_rewind( ProxyConnection* conn ); - -/* base64 encode a source string, returns size of encoded result, - * or -1 if there was not enough room in the destination buffer - */ -extern int -proxy_base64_encode( const char* src, int srclen, - char* dst, int dstlen ); - -extern int -proxy_resolve_server( SockAddress* addr, - const char* servername, - int servernamelen, - int serverport ); - -/* a ProxyService is really a proxy server and associated options */ - -/* destroy a given proxy service */ -typedef void (*ProxyServiceFreeFunc) ( void* opaque ); - -/* tries to create a new proxified connection, returns NULL if the service can't - * handle this address */ -typedef ProxyConnection* (*ProxyServiceConnectFunc)( void* opaque, - SocketType socket_type, - const SockAddress* address ); - -struct ProxyService { - void* opaque; - ProxyServiceFreeFunc serv_free; - ProxyServiceConnectFunc serv_connect; -}; - -extern int -proxy_manager_add_service( ProxyService* service ); - - -#endif /* _PROXY_INT_H */ -- cgit v1.1