diff options
Diffstat (limited to 'proxy/proxy_http.c')
-rw-r--r-- | proxy/proxy_http.c | 235 |
1 files changed, 31 insertions, 204 deletions
diff --git a/proxy/proxy_http.c b/proxy/proxy_http.c index 83982a7..c3d663c 100644 --- a/proxy/proxy_http.c +++ b/proxy/proxy_http.c @@ -10,200 +10,18 @@ ** GNU General Public License for more details. */ #include "proxy_int.h" -#include "proxy_http.h" +#include "proxy_http_int.h" #include <errno.h> #include <stdio.h> #include <string.h> #include "vl.h" -typedef enum { - HTTP_NONE = 0, - HTTP_CONNECTING, /* connecting to the server */ - HTTP_SEND_HEADER, /* connected, sending header to the server */ - HTTP_RECEIVE_ANSWER_LINE1, - HTTP_RECEIVE_ANSWER_LINE2 /* connected, reading server's answer */ -} HttpConnectionState; - - -typedef struct { - ProxyConnection root[1]; - HttpConnectionState state; -} HttpConnection; - - -typedef struct { - ProxyService root[1]; - struct sockaddr_in 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; - - -static void -http_connection_free( HttpConnection* conn ) -{ - proxy_connection_done(conn->root); - qemu_free(conn); -} - - #define HTTP_VERSION "1.1" -static int -http_connection_init( HttpConnection* conn ) -{ - HttpService* service = (HttpService*) conn->root->service; - ProxyConnection* root = conn->root; - char* p = root->buffer0; - char* end = p + sizeof(root->buffer0); - int wlen, ret; - uint32_t address = ntohl(conn->root->address.sin_addr.s_addr); - int port = ntohs(conn->root->address.sin_port); - - root->buffer_pos = 0; - root->buffer = p; - - p += snprintf(p, end-p, "CONNECT %d.%d.%d.%d:%d HTTP/" HTTP_VERSION "\r\n", - (address >> 24) & 0xff, (address >> 16) & 0xff, - (address >> 8) & 0xff, address & 0xff, port); - if (p >= end) goto Overflow; - - p += snprintf(p, end-p, "%.*s", service->footer_len, service->footer); - - if (p >= end) { - Overflow: - PROXY_LOG("%s: buffer overflow in proxy connection header\n", root->name); - return -1; - } - - root->buffer_len = (p - root->buffer); - - ret = connect( root->socket, - (struct sockaddr*) &service->server_addr, - sizeof(service->server_addr) ); - if (ret == 0) { - /* immediate connection ?? */ - conn->state = HTTP_SEND_HEADER; - PROXY_LOG("%s: immediate connection\n", root->name); - } - else { - if (socket_errno == EINPROGRESS || socket_errno == EWOULDBLOCK) { - conn->state = HTTP_CONNECTING; - PROXY_LOG("%s: connecting\n", conn->root->name); - } - else { - PROXY_LOG("%s: cannot connect to proxy: %s\n", root->name, strerror(errno)); - return -1; - } - } - return 0; -} - - -static unsigned -http_connection_select( HttpConnection* conn ) -{ - unsigned flags; - - switch (conn->state) { - case HTTP_RECEIVE_ANSWER_LINE1: - case HTTP_RECEIVE_ANSWER_LINE2: - flags = PROXY_SELECT_READ; - break; - - case HTTP_CONNECTING: - case HTTP_SEND_HEADER: - flags = PROXY_SELECT_WRITE; - break; - - default: - flags = 0; - }; - return flags; -} - -static void -http_connection_poll( HttpConnection* conn, - unsigned flags ) -{ - int ret; - ProxyConnection* root = conn->root; - - switch (conn->state) - { - case HTTP_CONNECTING: - PROXY_LOG("%s: connected to http proxy, sending header\n", root->name); - conn->state = HTTP_SEND_HEADER; - break; - - case HTTP_SEND_HEADER: - { - int ret = proxy_connection_send(root); - - if (ret < 0) { - proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR ); - return; - } - if (ret == 0) - return; - - root->buffer_len = sizeof(root->buffer0); - root->buffer_pos = 0; - conn->state = HTTP_RECEIVE_ANSWER_LINE1; - PROXY_LOG("%s: header sent, receiving first answer line\n", root->name); - } - break; - - case HTTP_RECEIVE_ANSWER_LINE1: - case HTTP_RECEIVE_ANSWER_LINE2: - { - int ret = proxy_connection_receive_line(root); - - if (ret < 0) { - proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR ); - return; - } - if (ret == 0) - return; - - if (conn->state == HTTP_RECEIVE_ANSWER_LINE1) { - int http1, http2, codenum; - - if ( sscanf(root->buffer, "HTTP/%d.%d %d", &http1, &http2, &codenum) != 3 ) { - PROXY_LOG( "%s: invalid answer from proxy: '%s'\n", - root->name, root->buffer ); - proxy_connection_free( root, PROXY_EVENT_SERVER_ERROR ); - return; - } - - /* success is 2xx */ - if (codenum/2 != 100) { - PROXY_LOG( "%s: connection refused, error=%d\n", - root->name, codenum ); - proxy_connection_free( root, PROXY_EVENT_CONNECTION_REFUSED ); - return; - } - PROXY_LOG("%s: receiving second answer line\n", root->name); - conn->state = HTTP_RECEIVE_ANSWER_LINE2; - root->buffer_pos = 0; - } else { - /* ok, we're connected */ - PROXY_LOG("%s: connection succeeded\n", root->name); - proxy_connection_free( root, PROXY_EVENT_CONNECTED ); - } - } - break; - - default: - PROXY_LOG("%s: invalid state for read event: %d\n", root->name, conn->state); - } -} - static void http_service_free( HttpService* service ) { - PROXY_LOG("%s\n", __FUNCTION__); + PROXY_LOG("%s", __FUNCTION__); if (service->footer != service->footer0) qemu_free(service->footer); qemu_free(service); @@ -212,11 +30,11 @@ http_service_free( HttpService* service ) static ProxyConnection* http_service_connect( HttpService* service, - int socket, + int sock_type, struct sockaddr_in* address ) { - HttpConnection* conn = qemu_mallocz(sizeof(*conn)); - int sock_type = socket_get_type(socket); + uint32_t addr; + int port; /* the HTTP proxy can only handle TCP connections */ if (sock_type != SOCK_STREAM) @@ -227,14 +45,25 @@ http_service_connect( HttpService* service, address->sin_port == service->server_addr.sin_port) return NULL; - proxy_connection_init( conn->root, socket, address, service->root ); - - if ( http_connection_init( conn ) < 0 ) { - http_connection_free( conn ); - return NULL; + addr = ntohl(address->sin_addr.s_addr); + port = ntohs(address->sin_port); + + PROXY_LOG("%s: trying to connect to %d.%d.%d.%d on port %d", + __FUNCTION__, + (addr >> 24) & 255, + (addr >> 16) & 255, + (addr >> 8) & 255, + addr & 255, + port ); + + if (port == 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); } - - return conn->root; } @@ -256,7 +85,7 @@ proxy_http_setup( const char* servername, if (servernamelen < 0) servernamelen = strlen(servername); - PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d\n", + PROXY_LOG( "%s: creating http proxy service connecting to: %.*s:%d", __FUNCTION__, servernamelen, servername, serverport ); /* resolve server address */ @@ -269,7 +98,7 @@ proxy_http_setup( const char* servername, /* create service object */ service = qemu_mallocz(sizeof(*service)); if (service == NULL) { - PROXY_LOG("%s: not enough memory to allocate new proxy service\n", __FUNCTION__); + PROXY_LOG("%s: not enough memory to allocate new proxy service", __FUNCTION__); return -1; } @@ -322,7 +151,7 @@ proxy_http_setup( const char* servername, wlen = proxy_base64_encode(user_pass, uplen, encoded, (int)sizeof(encoded)); if (wlen < 0) { - PROXY_LOG( "could not base64 encode '%.*s'\n", uplen, user_pass); + PROXY_LOG( "could not base64 encode '%.*s'", uplen, user_pass); goto FooterOverflow; } @@ -341,7 +170,7 @@ proxy_http_setup( const char* servername, if (p >= end) { FooterOverflow: - PROXY_LOG( "%s: buffer overflow when creating connection footer\n", + PROXY_LOG( "%s: buffer overflow when creating connection footer", __FUNCTION__); http_service_free(service); return -1; @@ -351,18 +180,16 @@ proxy_http_setup( const char* servername, service->footer_len = (p - service->footer); } - PROXY_LOG( "%s: creating HTTP Proxy Service Footer is (len=%d):\n'%.*s'\n", + 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; - service->root->conn_free = (ProxyConnectionFreeFunc) http_connection_free; - service->root->conn_select = (ProxyConnectionSelectFunc) http_connection_select; - service->root->conn_poll = (ProxyConnectionPollFunc) http_connection_poll; + 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; } |