diff options
-rw-r--r-- | src/IO/http.c | 156 |
1 files changed, 85 insertions, 71 deletions
diff --git a/src/IO/http.c b/src/IO/http.c index e5c459ee..22b2eaa6 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -57,13 +57,13 @@ static const int HTTP_SOCKET_SSL = 0x8; /* 'web' is just a reference (no need to deallocate it here). */ typedef struct { int SockFD; - uint_t connect_port; uint_t flags; DilloWeb *web; /* reference to client's web structure */ DilloUrl *url; Dlist *addr_list; /* Holds the DNS answer */ ChainLink *Info; /* Used for CCC asynchronous operations */ - char *connected_to; /* Used for per-host connection limit */ + char *connected_to; /* Used for per-server connection limit */ + uint_t connect_port; Dstr *https_proxy_reply; } SocketData_t; @@ -72,19 +72,22 @@ typedef struct { */ typedef struct { char *host; + uint_t port; + bool_t https; + int active_conns; Dlist *queue; -} HostConnection_t; +} Server_t; typedef struct { int fd; int skey; } FdMapEntry_t; -static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock); -static HostConnection_t *Http_host_connection_get(const char *host); -static void Http_host_connection_remove(HostConnection_t *hc); -static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc); +static void Http_socket_enqueue(Server_t *srv, SocketData_t* sock); +static Server_t *Http_server_get(const char *host, uint_t port, bool_t https); +static void Http_server_remove(Server_t *srv); +static void Http_connect_socket(ChainLink *Info); static char *Http_get_connect_str(const DilloUrl *url); static void Http_send_query(SocketData_t *S); static void Http_socket_free(int SKey); @@ -97,7 +100,7 @@ static Klist_t *ValidSocks = NULL; /* Active sockets list. It holds pointers to static DilloUrl *HTTP_Proxy = NULL; static char *HTTP_Proxy_Auth_base64 = NULL; static char *HTTP_Language_hdr = NULL; -static Dlist *host_connections; +static Dlist *servers; /* TODO: If fd_map will stick around in its present form (FDs and SocketData_t) * then consider whether having both this and ValidSocks is necessary. @@ -127,7 +130,7 @@ int a_Http_init(void) HTTP_Proxy_Auth_base64 = a_Misc_encode_base64(prefs.http_proxyuser); */ - host_connections = dList_new(5); + servers = dList_new(5); fd_map = dList_new(20); return 0; @@ -228,23 +231,24 @@ void a_Http_connect_done(int fd, bool_t success) } } -static void Http_socket_activate(HostConnection_t *hc, SocketData_t *sd) +static void Http_socket_activate(Server_t *srv, SocketData_t *sd) { - dList_remove(hc->queue, sd); + dList_remove(srv->queue, sd); sd->flags &= ~HTTP_SOCKET_QUEUED; - hc->active_conns++; - sd->connected_to = hc->host; + srv->active_conns++; + sd->connected_to = srv->host; } -static void Http_connect_queued_sockets(HostConnection_t *hc) +static void Http_connect_queued_sockets(Server_t *srv) { SocketData_t *sd; int i; for (i = 0; - i < dList_length(hc->queue) && hc->active_conns < prefs.http_max_conns; + (i < dList_length(srv->queue) && + srv->active_conns < prefs.http_max_conns); i++) { - sd = dList_nth_data(hc->queue, i); + sd = dList_nth_data(srv->queue, i); if (!(sd->flags & HTTP_SOCKET_TO_BE_FREED)) { int connect_ready = SSL_CONNECT_READY; @@ -258,18 +262,19 @@ static void Http_connect_queued_sockets(HostConnection_t *hc) Http_socket_free(SKey); } else if (connect_ready == SSL_CONNECT_READY) { i--; - Http_socket_activate(hc, sd); - Http_connect_socket(sd->Info, hc); + Http_socket_activate(srv, sd); + Http_connect_socket(sd->Info); } } if (sd->flags & HTTP_SOCKET_TO_BE_FREED) { - dList_remove(hc->queue, sd); + dList_remove(srv->queue, sd); dFree(sd); i--; } } - _MSG("Queue %s len %d\n", hc->host, dList_length(hc->queue)); + _MSG("Queue http%s://%s:%u len %d\n", srv->https ? "s" : "", srv->host, + srv->port, dList_length(srv->queue)); } /* @@ -294,11 +299,12 @@ static void Http_socket_free(int SKey) if (S->connected_to) { a_Ssl_close_by_fd(S->SockFD); - HostConnection_t *hc = Http_host_connection_get(S->connected_to); - hc->active_conns--; - Http_connect_queued_sockets(hc); - if (hc->active_conns == 0) - Http_host_connection_remove(hc); + Server_t *srv = Http_server_get(S->connected_to, S->connect_port, + (S->flags & HTTP_SOCKET_SSL)); + srv->active_conns--; + Http_connect_queued_sockets(srv); + if (srv->active_conns == 0) + Http_server_remove(srv); } a_Url_free(S->url); dFree(S); @@ -504,7 +510,7 @@ static void Http_connect_ssl(ChainLink *info) * This function is called after the DNS succeeds in solving a hostname. * Task: Finish socket setup and start connecting the socket. */ -static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) +static void Http_connect_socket(ChainLink *Info) { int i, status; SocketData_t *S; @@ -542,7 +548,7 @@ static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) sin->sin_port = htons(S->connect_port); memcpy(&sin->sin_addr, dh->data, (size_t)dh->alen); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) - MSG("Connecting to %s:%d\n", inet_ntoa(sin->sin_addr), + MSG("Connecting to %s:%u\n", inet_ntoa(sin->sin_addr), S->connect_port); break; } @@ -557,7 +563,7 @@ static void Http_connect_socket(ChainLink *Info, HostConnection_t *hc) memcpy(&sin6->sin6_addr, dh->data, dh->alen); inet_ntop(dh->af, dh->data, buf, sizeof(buf)); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) - MSG("Connecting to %s:%d\n", buf, S->connect_port); + MSG("Connecting to %s:%u\n", buf, S->connect_port); break; } #endif @@ -658,7 +664,7 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data) int SKey = VOIDP2INT(data); bool_t clean_up = TRUE; SocketData_t *S; - HostConnection_t *hc; + Server_t *srv; S = a_Klist_get_data(ValidSocks, SKey); if (S) { @@ -670,9 +676,10 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data) /* Successful DNS answer; save the IP */ S->addr_list = addr_list; clean_up = FALSE; - hc = Http_host_connection_get(host); - Http_socket_enqueue(hc, S); - Http_connect_queued_sockets(hc); + srv = Http_server_get(host, S->connect_port, + (S->flags & HTTP_SOCKET_SSL)); + Http_socket_enqueue(srv, S); + Http_connect_queued_sockets(srv); } else { /* DNS wasn't able to resolve the hostname */ MSG_BW(S->web, 0, "ERROR: DNS can't resolve %s", host); @@ -734,15 +741,17 @@ static int Http_get(ChainLink *Info, void *Data1) /* * Can the old socket's fd be reused for the new socket? * - * NOTE: old and new must come from the same HostConnection_t. + * NOTE: old and new must come from the same Server_t. * This is not built to accept arbitrary sockets. */ static bool_t Http_socket_reuse_compatible(SocketData_t *old, SocketData_t *new) { + /* + * If we are using SSL through a proxy, we need to ensure that old and new + * are going through to the same host:port. + */ if (a_Web_valid(new->web) && - old->connect_port == new->connect_port && - ((old->flags & HTTP_SOCKET_SSL) == (new->flags & HTTP_SOCKET_SSL)) && ((old->flags & HTTP_SOCKET_SSL) == 0 || (old->flags & HTTP_SOCKET_USE_PROXY) == 0 || ((URL_PORT(old->url) == URL_PORT(new->url)) && @@ -760,11 +769,13 @@ static void Http_socket_reuse(int SKey) SocketData_t *new_sd, *old_sd = a_Klist_get_data(ValidSocks, SKey); if (old_sd) { - HostConnection_t *hc = Http_host_connection_get(old_sd->connected_to); - int i, n = dList_length(hc->queue); + Server_t *srv = Http_server_get(old_sd->connected_to, + old_sd->connect_port, + (old_sd->flags & HTTP_SOCKET_SSL)); + int i, n = dList_length(srv->queue); for (i = 0; i < n; i++) { - new_sd = dList_nth_data(hc->queue, i); + new_sd = dList_nth_data(srv->queue, i); if (!(new_sd->flags & HTTP_SOCKET_TO_BE_FREED) && Http_socket_reuse_compatible(old_sd, new_sd)) { @@ -773,11 +784,11 @@ static void Http_socket_reuse(int SKey) new_sd->SockFD = old_sd->SockFD; old_sd->connected_to = NULL; - hc->active_conns--; + srv->active_conns--; Http_socket_free(SKey); MSG("Reusing fd %d for %s\n", new_sd->SockFD,URL_STR(new_sd->url)); - Http_socket_activate(hc, new_sd); + Http_socket_activate(srv, new_sd); Http_fd_map_add_entry(new_sd); a_Http_connect_done(new_sd->SockFD, success); return; @@ -935,68 +946,71 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, * Add socket data to the queue. Pages/stylesheets/etc. have higher priority * than images. */ -static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock) +static void Http_socket_enqueue(Server_t *srv, SocketData_t* sock) { sock->flags |= HTTP_SOCKET_QUEUED; if ((sock->web->flags & WEB_Image) == 0) { - int i, n = dList_length(hc->queue); + int i, n = dList_length(srv->queue); for (i = 0; i < n; i++) { - SocketData_t *curr = dList_nth_data(hc->queue, i); + SocketData_t *curr = dList_nth_data(srv->queue, i); if (a_Web_valid(curr->web) && (curr->web->flags & WEB_Image)) { - dList_insert_pos(hc->queue, sock, i); + dList_insert_pos(srv->queue, sock, i); return; } } } - dList_append(hc->queue, sock); + dList_append(srv->queue, sock); } -static HostConnection_t *Http_host_connection_get(const char *host) +static Server_t *Http_server_get(const char *host, uint_t port, bool_t https) { int i; - HostConnection_t *hc; + Server_t *srv; - for (i = 0; i < dList_length(host_connections); i++) { - hc = (HostConnection_t*) dList_nth_data(host_connections, i); + for (i = 0; i < dList_length(servers); i++) { + srv = (Server_t*) dList_nth_data(servers, i); - if (dStrAsciiCasecmp(host, hc->host) == 0) - return hc; + if (port == srv->port && https == srv->https && + !dStrAsciiCasecmp(host, srv->host)) + return srv; } - hc = dNew0(HostConnection_t, 1); - hc->queue = dList_new(10); - hc->host = dStrdup(host); - dList_append(host_connections, hc); + srv = dNew0(Server_t, 1); + srv->queue = dList_new(10); + srv->host = dStrdup(host); + srv->port = port; + srv->https = https; + dList_append(servers, srv); - return hc; + return srv; } -static void Http_host_connection_remove(HostConnection_t *hc) +static void Http_server_remove(Server_t *srv) { - assert(dList_length(hc->queue) == 0); - dList_free(hc->queue); - dList_remove_fast(host_connections, hc); - dFree(hc->host); - dFree(hc); + assert(dList_length(srv->queue) == 0); + dList_free(srv->queue); + dList_remove_fast(servers, srv); + dFree(srv->host); + dFree(srv); } -static void Http_host_connection_remove_all() +static void Http_servers_remove_all() { - HostConnection_t *hc; + Server_t *srv; SocketData_t *sd; - while (dList_length(host_connections) > 0) { - hc = (HostConnection_t*) dList_nth_data(host_connections, 0); - while ((sd = dList_nth_data(hc->queue, 0))) { - dList_remove(hc->queue, sd); + while (dList_length(servers) > 0) { + srv = (Server_t*) dList_nth_data(servers, 0); + while ((sd = dList_nth_data(srv->queue, 0))) { + dList_remove(srv->queue, sd); dFree(sd); } - Http_host_connection_remove(hc); + Http_server_remove(srv); } - dList_free(host_connections); + dList_free(servers); } static void Http_fd_map_remove_all() @@ -1017,7 +1031,7 @@ static void Http_fd_map_remove_all() */ void a_Http_freeall(void) { - Http_host_connection_remove_all(); + Http_servers_remove_all(); Http_fd_map_remove_all(); a_Klist_free(&ValidSocks); a_Url_free(HTTP_Proxy); |