aboutsummaryrefslogtreecommitdiff
path: root/src/IO/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/IO/http.c')
-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);