summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcorvid <devnull@localhost>2015-05-28 16:58:39 +0000
committercorvid <devnull@localhost>2015-05-28 16:58:39 +0000
commitea14c266b84296761354f63d746a289db0bb4918 (patch)
treeff1a67fef44141af96e8f5f95815c85db493eb06
parentaf2f4800e97d5f9ae3a43062cdac0425362cccba (diff)
make http_max_conns truly per server/proxy rather than host
And separate http from https for safety while we're at it. We were checking this where we needed to, but it would be easy to forget about in the future. Not that very much happens when you try http://example.com:443 or https://example.com:80, but I'm being careful nevertheless.
-rw-r--r--src/IO/http.c156
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);