aboutsummaryrefslogtreecommitdiff
path: root/src/IO/http.c
diff options
context:
space:
mode:
authorSebastian Geerken <devnull@localhost>2014-07-18 15:58:48 +0200
committerSebastian Geerken <devnull@localhost>2014-07-18 15:58:48 +0200
commit9d9b0c76a3b04a8ea5971e9d9cc8c9cd790b8b49 (patch)
tree5a92fe13eca24a03189ce8c8a79dc1d26b89336d /src/IO/http.c
parent441370fa67c40a47916b7a44d4fa1d18feadb6dd (diff)
parent531843c893ae53a61d7278630a5061a63a251ded (diff)
Merge with main repo.
Diffstat (limited to 'src/IO/http.c')
-rw-r--r--src/IO/http.c142
1 files changed, 116 insertions, 26 deletions
diff --git a/src/IO/http.c b/src/IO/http.c
index a0021a9e..1be94e0d 100644
--- a/src/IO/http.c
+++ b/src/IO/http.c
@@ -79,16 +79,18 @@ typedef struct {
typedef struct {
char *host;
- int active_connections;
- SocketQueue_t queue;
+ Dlist *active_fds;
+ int avail_fd;
+ SocketQueue_t main_q, image_q; /* imgs have separate lower-priority queue */
} HostConnection_t;
static void Http_socket_queue_init(SocketQueue_t *sq);
-static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock);
-static SocketData_t* Http_socket_dequeue(SocketQueue_t *sq);
+static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock);
+static SocketData_t* Http_socket_dequeue(HostConnection_t *hc);
static HostConnection_t *Http_host_connection_get(const char *host);
static void Http_host_connection_remove(HostConnection_t *hc);
static int Http_connect_socket(ChainLink *Info);
+static void Http_send_query(ChainLink *Info, SocketData_t *S);
static void Http_socket_free(int SKey);
/*
@@ -160,9 +162,10 @@ static int Http_sock_new(void)
static void Http_connect_queued_sockets(HostConnection_t *hc)
{
+ bool_t all_is_well = TRUE;
SocketData_t *sd;
- while (hc->active_connections < prefs.http_max_conns &&
- (sd = Http_socket_dequeue(&hc->queue))) {
+ while (dList_length(hc->active_fds) < prefs.http_max_conns &&
+ (sd = Http_socket_dequeue(hc))) {
sd->flags &= ~HTTP_SOCKET_QUEUED;
@@ -170,18 +173,30 @@ static void Http_connect_queued_sockets(HostConnection_t *hc)
dFree(sd);
} else if (a_Web_valid(sd->web)) {
/* start connecting the socket */
- if (Http_connect_socket(sd->Info) < 0) {
+ if (hc->avail_fd != -1) {
+ sd->SockFD = hc->avail_fd;
+ hc->avail_fd = -1;
+ } else if (Http_connect_socket(sd->Info) < 0) {
ChainLink *Info = sd->Info;
+ all_is_well = FALSE;
MSG_BW(sd->web, 1, "ERROR: %s", dStrerror(sd->Err));
a_Chain_bfcb(OpAbort, Info, NULL, "Both");
Http_socket_free(VOIDP2INT(Info->LocalKey)); /* free sd */
dFree(Info);
- } else {
+ }
+ if (all_is_well) {
+ a_Chain_bcb(OpSend, sd->Info, &sd->SockFD, "FD");
+ a_Chain_fcb(OpSend, sd->Info, &sd->SockFD, "FD");
+ Http_send_query(sd->Info, sd);
sd->connected_to = hc->host;
- hc->active_connections++;
+ dList_append(hc->active_fds, (void *)sd->SockFD);
}
}
}
+ if (hc->avail_fd != -1) {
+ dClose(hc->avail_fd);
+ hc->avail_fd = -1;
+ }
}
/*
@@ -199,9 +214,9 @@ static void Http_socket_free(int SKey)
} else {
if (S->connected_to) {
HostConnection_t *hc = Http_host_connection_get(S->connected_to);
- hc->active_connections--;
+ dList_remove_fast(hc->active_fds, (void *)S->SockFD);
Http_connect_queued_sockets(hc);
- if (hc->active_connections == 0)
+ if (dList_length(hc->active_fds) == 0)
Http_host_connection_remove(hc);
}
dFree(S);
@@ -275,6 +290,10 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
web_flags & WEB_Stylesheet ? "text/css,*/*;q=0.1" :
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
+ const char *connection_hdr_val =
+ (prefs.http_persistent_conns == TRUE &&
+ !dStrAsciiCasecmp(URL_SCHEME(url), "http")) ? "keep-alive" : "close";
+
if (use_proxy) {
dStr_sprintfa(request_uri, "%s%s",
URL_STR(url),
@@ -309,15 +328,15 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
"DNT: 1\r\n"
"%s" /* proxy auth */
"%s" /* referer */
- "Connection: close\r\n"
+ "Connection: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n"
"%s" /* cookies */
"\r\n",
request_uri->str, URL_AUTHORITY(url), prefs.http_user_agent,
accept_hdr_value, HTTP_Language_hdr, auth ? auth : "",
- proxy_auth->str, referer, content_type->str, (long)URL_DATA(url)->len,
- cookies);
+ proxy_auth->str, referer, connection_hdr_val, content_type->str,
+ (long)URL_DATA(url)->len, cookies);
dStr_append_l(query, URL_DATA(url)->str, URL_DATA(url)->len);
dStr_free(content_type, TRUE);
} else {
@@ -333,13 +352,13 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester,
"DNT: 1\r\n"
"%s" /* proxy auth */
"%s" /* referer */
- "Connection: close\r\n"
+ "Connection: %s\r\n"
"%s" /* cache control */
"%s" /* cookies */
"\r\n",
request_uri->str, URL_AUTHORITY(url), prefs.http_user_agent,
accept_hdr_value, HTTP_Language_hdr, auth ? auth : "",
- proxy_auth->str, referer,
+ proxy_auth->str, referer, connection_hdr_val,
(URL_FLAGS(url) & URL_E2EQuery) ?
"Pragma: no-cache\r\nCache-Control: no-cache\r\n" : "",
cookies);
@@ -447,9 +466,6 @@ static int Http_connect_socket(ChainLink *Info)
dClose(S->SockFD);
MSG("Http_connect_socket ERROR: %s\n", dStrerror(S->Err));
} else {
- a_Chain_bcb(OpSend, Info, &S->SockFD, "FD");
- a_Chain_fcb(OpSend, Info, &S->SockFD, "FD");
- Http_send_query(S->Info, S);
return 0; /* Success */
}
}
@@ -491,7 +507,6 @@ static int Http_must_use_proxy(const DilloUrl *url)
/*
* Return a new string for the request used to tunnel HTTPS through a proxy.
- * As of 2009, the best reference appears to be section 5 of RFC 2817.
*/
char *a_Http_make_connect_str(const DilloUrl *url)
{
@@ -565,7 +580,7 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data)
hc = Http_host_connection_get(URL_HOST(HTTP_Proxy));
else
hc = Http_host_connection_get(URL_HOST(S->web->url));
- Http_socket_enqueue(&hc->queue, S);
+ Http_socket_enqueue(hc, S);
Http_connect_queued_sockets(hc);
} else {
/* DNS wasn't able to resolve the hostname */
@@ -619,6 +634,28 @@ static int Http_get(ChainLink *Info, void *Data1)
return 0;
}
+static void Http_make_fd_available(int fd)
+{
+ int i, j;
+
+ for (i = 0; i < dList_length(host_connections); i++) {
+ HostConnection_t *hc =
+ (HostConnection_t*) dList_nth_data(host_connections, i);
+
+ for (j = 0; j < dList_length(hc->active_fds); j++) {
+ void *data = dList_nth_data(hc->active_fds, j);
+
+ if (fd == VOIDP2INT(data)) {
+ _MSG("host %s ", hc->host);
+ _MSG("Shift fd %d from active to avail\n", fd);
+ dList_remove_fast (hc->active_fds, data);
+ hc->avail_fd = fd;
+ return;
+ }
+ }
+ }
+}
+
/*
* CCC function for the HTTP module
*/
@@ -666,6 +703,51 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info,
break;
}
}
+ } else if (Branch == 2) {
+ if (Dir == FWD) {
+ /* Receiving from server */
+ switch (Op) {
+ case OpSend:
+ /* Data1 = dbuf */
+ a_Chain_fcb(OpSend, Info, Data1, "send_page_2eof");
+ break;
+ case OpEnd:
+ a_Chain_fcb(OpEnd, Info, NULL, NULL);
+ dFree(Info);
+ break;
+ default:
+ MSG_WARN("Unused CCC\n");
+ break;
+ }
+ } else { /* 2 BCK */
+ switch (Op) {
+ case OpStart:
+ a_Chain_link_new(Info, a_Http_ccc, BCK, a_IO_ccc, 2, 2);
+ a_Chain_bcb(OpStart, Info, NULL, NULL); /* IORead */
+ break;
+ case OpSend:
+ if (Data2) {
+ if (!strcmp(Data2, "FD")) {
+ Info->LocalKey = (void *)*(int*)Data1;
+ a_Chain_bcb(OpSend, Info, Data1, Data2);
+ } else if (!strcmp(Data2, "reply_complete")) {
+ int fd = VOIDP2INT(Info->LocalKey);
+
+ Http_make_fd_available(fd);
+ a_Chain_bfcb(OpEnd, Info, NULL, NULL);
+ dFree(Info);
+ }
+ }
+ break;
+ case OpAbort:
+ a_Chain_bcb(OpAbort, Info, NULL, NULL);
+ dFree(Info);
+ break;
+ default:
+ MSG_WARN("Unused CCC\n");
+ break;
+ }
+ }
}
}
@@ -676,13 +758,16 @@ static void Http_socket_queue_init(SocketQueue_t *sq)
sq->tail = NULL;
}
-static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock)
+static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock)
{
+ SocketQueue_t *sq;
SocketQueueEntry_t *se = dNew(SocketQueueEntry_t, 1);
se->sock = sock;
se->next = NULL;
+ sq = sock->web->flags & WEB_Image ? &hc->image_q : &hc->main_q;
+
if (sq->tail)
sq->tail->next = se;
sq->tail = se;
@@ -691,8 +776,9 @@ static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock)
sq->head = se;
}
-static SocketData_t* Http_socket_dequeue(SocketQueue_t *sq)
+static SocketData_t* Http_socket_dequeue(HostConnection_t *hc)
{
+ SocketQueue_t *sq = hc->main_q.head ? &hc->main_q : &hc->image_q;
SocketQueueEntry_t *se = sq->head;
SocketData_t *sd = NULL;
@@ -720,8 +806,11 @@ static HostConnection_t *Http_host_connection_get(const char *host)
}
hc = dNew0(HostConnection_t, 1);
- Http_socket_queue_init(&hc->queue);
+ Http_socket_queue_init(&hc->main_q);
+ Http_socket_queue_init(&hc->image_q);
hc->host = dStrdup(host);
+ hc->active_fds = dList_new(prefs.http_max_conns);
+ hc->avail_fd = -1;
dList_append(host_connections, hc);
return hc;
@@ -729,9 +818,10 @@ static HostConnection_t *Http_host_connection_get(const char *host)
static void Http_host_connection_remove(HostConnection_t *hc)
{
- assert(hc->queue.head == NULL);
+ assert(hc->main_q.head == NULL && hc->image_q.head == NULL);
dList_remove_fast(host_connections, hc);
dFree(hc->host);
+ dList_free(hc->active_fds);
dFree(hc);
}
@@ -741,7 +831,7 @@ static void Http_host_connection_remove_all()
while (dList_length(host_connections) > 0) {
hc = (HostConnection_t*) dList_nth_data(host_connections, 0);
- while (Http_socket_dequeue(&hc->queue));
+ while (Http_socket_dequeue(hc));
Http_host_connection_remove(hc);
}
dList_free(host_connections);