add ISC_MAGIC and reference counting to httpd and httpdmgr
This commit is contained in:
157
lib/isc/httpd.c
157
lib/isc/httpd.c
@@ -20,6 +20,7 @@
|
||||
#include <isc/httpd.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/print.h>
|
||||
#include <isc/refcount.h>
|
||||
#include <isc/socket.h>
|
||||
#include <isc/string.h>
|
||||
#include <isc/task.h>
|
||||
@@ -61,10 +62,19 @@
|
||||
#define HTTPD_CLOSE 0x0001 /* Got a Connection: close header */
|
||||
#define HTTPD_FOUNDHOST 0x0002 /* Got a Host: header */
|
||||
#define HTTPD_KEEPALIVE 0x0004 /* Got a Connection: Keep-Alive */
|
||||
#define HTTPD_ACCEPT_DEFLATE 0x0008
|
||||
#define HTTPD_ACCEPT_DEFLATE 0x0008
|
||||
|
||||
#define HTTPD_MAGIC ISC_MAGIC('H', 't', 'p', 'd')
|
||||
#define VALID_HTTPD(m) ISC_MAGIC_VALID(m, HTTPD_MAGIC)
|
||||
|
||||
#define HTTPDMGR_MAGIC ISC_MAGIC('H', 'p', 'd', 'm')
|
||||
#define VALID_HTTPDMGR(m) ISC_MAGIC_VALID(m, HTTPDMGR_MAGIC)
|
||||
|
||||
|
||||
/*% http client */
|
||||
struct isc_httpd {
|
||||
unsigned int magic; /* HTTPD_MAGIC */
|
||||
isc_refcount_t references;
|
||||
isc_httpdmgr_t *mgr; /*%< our parent */
|
||||
ISC_LINK(isc_httpd_t) link;
|
||||
unsigned int state;
|
||||
@@ -126,6 +136,8 @@ struct isc_httpd {
|
||||
|
||||
/*% lightweight socket manager for httpd output */
|
||||
struct isc_httpdmgr {
|
||||
unsigned int magic; /* HTTPDMGR_MAGIC */
|
||||
isc_refcount_t references;
|
||||
isc_mem_t *mctx;
|
||||
isc_socket_t *sock; /*%< listening socket */
|
||||
isc_task_t *task; /*%< owning task */
|
||||
@@ -222,8 +234,14 @@ destroy_client(isc_httpd_t **httpdp) {
|
||||
|
||||
*httpdp = NULL;
|
||||
|
||||
if (isc_refcount_decrement(&httpd->references) != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK(&httpdmgr->lock);
|
||||
|
||||
httpd->magic = 0;
|
||||
isc_refcount_destroy(&httpd->references);
|
||||
isc_socket_detach(&httpd->sock);
|
||||
ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
|
||||
|
||||
@@ -280,6 +298,8 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
||||
ISC_LIST_INIT(httpdmgr->running);
|
||||
ISC_LIST_INIT(httpdmgr->urls);
|
||||
|
||||
isc_refcount_init(&httpdmgr->references, 1);
|
||||
|
||||
/* XXXMLG ignore errors on isc_socket_listen() */
|
||||
result = isc_socket_listen(sock, SOMAXCONN);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
@@ -291,17 +311,24 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
||||
|
||||
(void)isc_socket_filter(sock, "httpready");
|
||||
|
||||
result = isc_socket_accept(sock, task, isc_httpd_accept, httpdmgr);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup;
|
||||
|
||||
httpdmgr->render_404 = render_404;
|
||||
httpdmgr->render_500 = render_500;
|
||||
httpdmgr->magic = HTTPDMGR_MAGIC;
|
||||
|
||||
isc_refcount_increment(&httpdmgr->references);
|
||||
result = isc_socket_accept(sock, task, isc_httpd_accept, httpdmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
(void) isc_refcount_decrement(&httpdmgr->references);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*httpdmgrp = httpdmgr;
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup:
|
||||
httpdmgr->magic = 0;
|
||||
isc_refcount_decrement(&httpdmgr->references);
|
||||
isc_refcount_destroy(&httpdmgr->references);
|
||||
isc_task_detach(&httpdmgr->task);
|
||||
isc_socket_detach(&httpdmgr->sock);
|
||||
isc_mem_detach(&httpdmgr->mctx);
|
||||
@@ -312,27 +339,20 @@ isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
|
||||
|
||||
static void
|
||||
httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
|
||||
isc_mem_t *mctx;
|
||||
isc_httpdurl_t *url;
|
||||
|
||||
ENTER("httpdmgr_destroy");
|
||||
|
||||
if (isc_refcount_decrement(&httpdmgr->references) != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOCK(&httpdmgr->lock);
|
||||
|
||||
if (!MSHUTTINGDOWN(httpdmgr)) {
|
||||
NOTICE("httpdmgr_destroy not shutting down yet");
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
return;
|
||||
}
|
||||
httpdmgr->magic = 0;
|
||||
|
||||
/*
|
||||
* If all clients are not shut down, don't do anything yet.
|
||||
*/
|
||||
if (!ISC_LIST_EMPTY(httpdmgr->running)) {
|
||||
NOTICE("httpdmgr_destroy clients still active");
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
return;
|
||||
}
|
||||
INSIST(MSHUTTINGDOWN(httpdmgr));
|
||||
INSIST(ISC_LIST_EMPTY(httpdmgr->running));
|
||||
|
||||
NOTICE("httpdmgr_destroy detaching socket, task, and timermgr");
|
||||
|
||||
@@ -355,11 +375,11 @@ httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
isc_mutex_destroy(&httpdmgr->lock);
|
||||
|
||||
if (httpdmgr->ondestroy != NULL)
|
||||
if (httpdmgr->ondestroy != NULL) {
|
||||
(httpdmgr->ondestroy)(httpdmgr->cb_arg);
|
||||
|
||||
mctx = httpdmgr->mctx;
|
||||
isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t));
|
||||
}
|
||||
isc_refcount_destroy(&httpdmgr->references);
|
||||
isc_mem_putanddetach(&httpdmgr->mctx, httpdmgr, sizeof(isc_httpdmgr_t));
|
||||
|
||||
EXIT("httpdmgr_destroy");
|
||||
}
|
||||
@@ -634,6 +654,8 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
|
||||
|
||||
httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t));
|
||||
|
||||
isc_refcount_init(&httpd->references, 1);
|
||||
isc_refcount_increment(&httpdmgr->references);
|
||||
httpd->mgr = httpdmgr;
|
||||
ISC_LINK_INIT(httpd, link);
|
||||
ISC_LIST_APPEND(httpdmgr->running, httpd, link);
|
||||
@@ -652,20 +674,24 @@ isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
|
||||
isc_buffer_initnull(&httpd->bodybuffer);
|
||||
httpd->sendbuffer = NULL;
|
||||
reset_client(httpd);
|
||||
httpd->magic = HTTPD_MAGIC;
|
||||
|
||||
r.base = (unsigned char *)httpd->recvbuf;
|
||||
r.length = HTTP_RECVLEN - 1;
|
||||
result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
|
||||
httpd);
|
||||
/* FIXME!!! */
|
||||
POST(result);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
destroy_client(&httpd);
|
||||
}
|
||||
NOTICE("accept queued recv on socket");
|
||||
|
||||
requeue:
|
||||
isc_refcount_increment(&httpdmgr->references);
|
||||
result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept,
|
||||
httpdmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
/* XXXMLG what to do? Log failure... */
|
||||
int32_t refs = isc_refcount_decrement(&httpdmgr->references);
|
||||
INSIST(refs > 1);
|
||||
NOTICE("accept could not reaccept due to failure");
|
||||
}
|
||||
|
||||
@@ -834,24 +860,25 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
|
||||
if (sev->result != ISC_R_SUCCESS) {
|
||||
NOTICE("recv destroying client");
|
||||
destroy_client(&httpd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
result = process_request(httpd, sev->n);
|
||||
if (result == ISC_R_NOTFOUND) {
|
||||
if (httpd->recvlen >= HTTP_RECVLEN - 1) {
|
||||
destroy_client(&httpd);
|
||||
goto out;
|
||||
}
|
||||
r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
|
||||
r.length = HTTP_RECVLEN - httpd->recvlen - 1;
|
||||
/* check return code? */
|
||||
(void)isc_socket_recv(httpd->sock, &r, 1, task,
|
||||
isc_httpd_recvdone, httpd);
|
||||
isc_refcount_increment(&httpd->references);
|
||||
result = isc_socket_recv(httpd->sock, &r, 1, task,
|
||||
isc_httpd_recvdone, httpd);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
uint32_t refs = isc_refcount_decrement(&httpd->references);
|
||||
INSIST(refs > 1);
|
||||
}
|
||||
goto out;
|
||||
} else if (result != ISC_R_SUCCESS) {
|
||||
destroy_client(&httpd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -864,13 +891,16 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
isc_buffer_initnull(&httpd->bodybuffer);
|
||||
isc_time_now(&now);
|
||||
isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
|
||||
LOCK(&httpd->mgr->lock);
|
||||
url = ISC_LIST_HEAD(httpd->mgr->urls);
|
||||
while (url != NULL) {
|
||||
if (strcmp(httpd->url, url->url) == 0)
|
||||
break;
|
||||
url = ISC_LIST_NEXT(url, link);
|
||||
}
|
||||
if (url == NULL)
|
||||
UNLOCK(&httpd->mgr->lock);
|
||||
|
||||
if (url == NULL) {
|
||||
result = httpd->mgr->render_404(httpd->url, NULL,
|
||||
httpd->querystring,
|
||||
NULL, NULL,
|
||||
@@ -880,7 +910,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
&httpd->bodybuffer,
|
||||
&httpd->freecb,
|
||||
&httpd->freecb_arg);
|
||||
else
|
||||
} else {
|
||||
result = url->action(httpd->url, url,
|
||||
httpd->querystring,
|
||||
httpd->headers,
|
||||
@@ -888,6 +918,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
&httpd->retcode, &httpd->retmsg,
|
||||
&httpd->mimetype, &httpd->bodybuffer,
|
||||
&httpd->freecb, &httpd->freecb_arg);
|
||||
}
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
result = httpd->mgr->render_500(httpd->url, url,
|
||||
httpd->querystring,
|
||||
@@ -911,8 +942,9 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
#endif
|
||||
|
||||
isc_httpd_response(httpd);
|
||||
if ((httpd->flags & HTTPD_KEEPALIVE) != 0)
|
||||
if ((httpd->flags & HTTPD_KEEPALIVE) != 0) {
|
||||
isc_httpd_addheader(httpd, "Connection", "Keep-Alive");
|
||||
}
|
||||
isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
|
||||
isc_httpd_addheader(httpd, "Date", datebuf);
|
||||
isc_httpd_addheader(httpd, "Expires", datebuf);
|
||||
@@ -934,7 +966,7 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
if (is_compressed == true) {
|
||||
isc_httpd_addheader(httpd, "Content-Encoding", "deflate");
|
||||
isc_httpd_addheaderuint(httpd, "Content-Length",
|
||||
isc_buffer_usedlength(&httpd->compbuffer));
|
||||
isc_buffer_usedlength(&httpd->compbuffer));
|
||||
} else {
|
||||
isc_httpd_addheaderuint(httpd, "Content-Length",
|
||||
isc_buffer_usedlength(&httpd->bodybuffer));
|
||||
@@ -958,11 +990,16 @@ isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
|
||||
*/
|
||||
isc_buffer_usedregion(httpd->sendbuffer, &r);
|
||||
|
||||
/* check return code? */
|
||||
(void)isc_socket_send(httpd->sock, &r, task,
|
||||
isc_httpd_senddone, httpd);
|
||||
isc_refcount_increment(&httpd->references);
|
||||
result = isc_socket_send(httpd->sock, &r, task,
|
||||
isc_httpd_senddone, httpd);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
uint32_t refs = isc_refcount_decrement(&httpd->references);
|
||||
INSIST(refs > 1);
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_client(&httpd);
|
||||
isc_event_free(&ev);
|
||||
EXIT("recv");
|
||||
}
|
||||
@@ -971,8 +1008,11 @@ void
|
||||
isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
|
||||
isc_httpdmgr_t *httpdmgr;
|
||||
isc_httpd_t *httpd;
|
||||
|
||||
REQUIRE(httpdmgrp != NULL);
|
||||
httpdmgr = *httpdmgrp;
|
||||
*httpdmgrp = NULL;
|
||||
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
||||
|
||||
ENTER("isc_httpdmgr_shutdown");
|
||||
|
||||
@@ -991,6 +1031,8 @@ isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
|
||||
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
|
||||
httpdmgr_destroy(httpdmgr);
|
||||
|
||||
EXIT("isc_httpdmgr_shutdown");
|
||||
}
|
||||
|
||||
@@ -1019,6 +1061,8 @@ isc_httpd_response(isc_httpd_t *httpd) {
|
||||
isc_result_t result;
|
||||
unsigned int needlen;
|
||||
|
||||
REQUIRE(VALID_HTTPD(httpd));
|
||||
|
||||
needlen = strlen(httpd->protocol) + 1; /* protocol + space */
|
||||
needlen += 3 + 1; /* room for response code, always 3 bytes */
|
||||
needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */
|
||||
@@ -1035,15 +1079,16 @@ isc_httpd_response(isc_httpd_t *httpd) {
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
|
||||
const char *val)
|
||||
{
|
||||
isc_httpd_addheader(isc_httpd_t *httpd, const char *name, const char *val) {
|
||||
isc_result_t result;
|
||||
unsigned int needlen;
|
||||
|
||||
REQUIRE(VALID_HTTPD(httpd));
|
||||
|
||||
needlen = strlen(name); /* name itself */
|
||||
if (val != NULL)
|
||||
if (val != NULL) {
|
||||
needlen += 2 + strlen(val); /* :<space> and val */
|
||||
}
|
||||
needlen += 2; /* CRLF */
|
||||
|
||||
while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
|
||||
@@ -1065,6 +1110,8 @@ isc_result_t
|
||||
isc_httpd_endheaders(isc_httpd_t *httpd) {
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_HTTPD(httpd));
|
||||
|
||||
while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
|
||||
result = grow_headerspace(httpd);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
@@ -1080,6 +1127,8 @@ isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
|
||||
unsigned int needlen;
|
||||
char buf[sizeof "18446744073709551616"];
|
||||
|
||||
REQUIRE(VALID_HTTPD(httpd));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", val);
|
||||
|
||||
needlen = strlen(name); /* name itself */
|
||||
@@ -1101,6 +1150,9 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
|
||||
isc_httpd_t *httpd = ev->ev_arg;
|
||||
isc_region_t r;
|
||||
isc_socketevent_t *sev = (isc_socketevent_t *)ev;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(VALID_HTTPD(httpd));
|
||||
|
||||
ENTER("senddone");
|
||||
INSIST(ISC_HTTPD_ISSEND(httpd));
|
||||
@@ -1124,12 +1176,10 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
|
||||
}
|
||||
|
||||
if (sev->result != ISC_R_SUCCESS) {
|
||||
destroy_client(&httpd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if ((httpd->flags & HTTPD_CLOSE) != 0) {
|
||||
destroy_client(&httpd);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -1141,11 +1191,17 @@ isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
|
||||
|
||||
r.base = (unsigned char *)httpd->recvbuf;
|
||||
r.length = HTTP_RECVLEN - 1;
|
||||
/* check return code? */
|
||||
(void)isc_socket_recv(httpd->sock, &r, 1, task,
|
||||
isc_httpd_recvdone, httpd);
|
||||
|
||||
isc_refcount_increment(&httpd->references);
|
||||
result = isc_socket_recv(httpd->sock, &r, 1, task,
|
||||
isc_httpd_recvdone, httpd);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
uint32_t refs = isc_refcount_decrement(&httpd->references);
|
||||
INSIST(refs > 1);
|
||||
}
|
||||
|
||||
out:
|
||||
destroy_client(&httpd);
|
||||
isc_event_free(&ev);
|
||||
EXIT("senddone");
|
||||
}
|
||||
@@ -1188,6 +1244,8 @@ isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
|
||||
{
|
||||
isc_httpdurl_t *item;
|
||||
|
||||
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
||||
|
||||
if (url == NULL) {
|
||||
httpdmgr->render_404 = func;
|
||||
return (ISC_R_SUCCESS);
|
||||
@@ -1203,7 +1261,10 @@ isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
|
||||
isc_time_now(&item->loadtime);
|
||||
|
||||
ISC_LINK_INIT(item, link);
|
||||
|
||||
LOCK(&httpdmgr->lock);
|
||||
ISC_LIST_APPEND(httpdmgr->urls, item, link);
|
||||
UNLOCK(&httpdmgr->lock);
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user