2006-12-21 06:03:37 +00:00
|
|
|
/*
|
2018-02-23 09:53:12 +01:00
|
|
|
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
2006-12-21 06:03:37 +00:00
|
|
|
*
|
2016-06-27 14:56:38 +10:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
2018-02-23 09:53:12 +01:00
|
|
|
*
|
|
|
|
* See the COPYRIGHT file distributed with this work for additional
|
|
|
|
* information regarding copyright ownership.
|
2006-12-21 06:03:37 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*! \file */
|
|
|
|
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <inttypes.h>
|
2018-04-17 08:29:14 -07:00
|
|
|
#include <stdbool.h>
|
2018-03-28 14:19:37 +02:00
|
|
|
#include <string.h>
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
#include <isc/buffer.h>
|
|
|
|
#include <isc/httpd.h>
|
|
|
|
#include <isc/mem.h>
|
2020-07-09 19:36:10 -07:00
|
|
|
#include <isc/netmgr.h>
|
2015-05-23 14:21:51 +02:00
|
|
|
#include <isc/print.h>
|
2020-01-17 18:24:24 +11:00
|
|
|
#include <isc/refcount.h>
|
2006-12-21 06:03:37 +00:00
|
|
|
#include <isc/socket.h>
|
|
|
|
#include <isc/string.h>
|
2014-01-09 15:14:57 -08:00
|
|
|
#include <isc/time.h>
|
2006-12-21 06:03:37 +00:00
|
|
|
#include <isc/util.h>
|
|
|
|
|
2015-10-02 10:45:10 +02:00
|
|
|
#ifdef HAVE_ZLIB
|
|
|
|
#include <zlib.h>
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef HAVE_ZLIB */
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
#define CHECK(m) \
|
|
|
|
do { \
|
|
|
|
result = (m); \
|
|
|
|
if (result != ISC_R_SUCCESS) { \
|
|
|
|
goto cleanup; \
|
|
|
|
} \
|
|
|
|
} while (0)
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define HTTP_RECVLEN 1024
|
|
|
|
#define HTTP_SENDGROW 1024
|
2020-02-12 13:59:18 +01:00
|
|
|
#define HTTP_SEND_MAXLEN 10240
|
2020-01-17 18:24:24 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#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 */
|
2020-02-12 13:59:18 +01:00
|
|
|
#define HTTPD_ACCEPT_DEFLATE 0x0008
|
2020-01-17 18:24:24 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define HTTPD_MAGIC ISC_MAGIC('H', 't', 'p', 'd')
|
2020-02-12 13:59:18 +01:00
|
|
|
#define VALID_HTTPD(m) ISC_MAGIC_VALID(m, HTTPD_MAGIC)
|
2020-01-17 18:24:24 +11:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
#define HTTPDMGR_MAGIC ISC_MAGIC('H', 'p', 'd', 'm')
|
2020-02-12 13:59:18 +01:00
|
|
|
#define VALID_HTTPDMGR(m) ISC_MAGIC_VALID(m, HTTPDMGR_MAGIC)
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
/*%
|
|
|
|
* Client states.
|
|
|
|
*
|
|
|
|
* _RECV The client is waiting for data after starting a read.
|
|
|
|
* _SEND All data for a response has completed, and a reply was
|
|
|
|
* sent via a send call.
|
|
|
|
*/
|
|
|
|
|
|
|
|
typedef enum { RECV, SEND } state_t;
|
|
|
|
|
|
|
|
/*%
|
|
|
|
* HTTP methods.
|
|
|
|
*/
|
|
|
|
typedef enum { METHOD_UNKNOWN = 0, METHOD_GET = 1, METHOD_POST = 2 } method_t;
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
/*% http client */
|
|
|
|
struct isc_httpd {
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int magic; /* HTTPD_MAGIC */
|
2020-07-09 19:36:10 -07:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_httpdmgr_t *mgr; /*%< our parent */
|
|
|
|
ISC_LINK(isc_httpd_t) link;
|
2020-07-09 19:36:10 -07:00
|
|
|
|
|
|
|
isc_nmhandle_t *handle;
|
|
|
|
state_t state;
|
|
|
|
int flags;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
/*%
|
|
|
|
* Received data state.
|
|
|
|
*/
|
2020-02-13 14:44:37 -08:00
|
|
|
char recvbuf[HTTP_RECVLEN]; /*%< receive buffer */
|
|
|
|
uint32_t recvlen; /*%< length recv'd */
|
|
|
|
char *headers; /*%< set in process_request() */
|
2020-07-09 19:36:10 -07:00
|
|
|
method_t method;
|
2020-02-13 14:44:37 -08:00
|
|
|
char *url;
|
|
|
|
char *querystring;
|
|
|
|
char *protocol;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
/*%
|
|
|
|
* Transmit data state.
|
|
|
|
*
|
|
|
|
* This is the data buffer we will transmit.
|
|
|
|
*
|
|
|
|
* This free function pointer is filled in by the rendering function
|
|
|
|
* we call. The free function is called after the data is transmitted
|
|
|
|
* to the client.
|
|
|
|
*
|
|
|
|
* The bufflist is the list of buffers we are currently transmitting.
|
2020-01-20 12:37:57 +01:00
|
|
|
* The headerbuffer is where we render our headers to. If we run out
|
|
|
|
* of space when rendering a header, we will change the size of our
|
2006-12-21 06:03:37 +00:00
|
|
|
* buffer. We will not free it until we are finished, and will
|
|
|
|
* allocate an additional HTTP_SENDGROW bytes per header space grow.
|
|
|
|
*
|
2015-10-02 10:45:10 +02:00
|
|
|
* We currently use three buffers total, one for the headers (which
|
|
|
|
* we manage), another for the client to fill in (which it manages,
|
2006-12-21 06:03:37 +00:00
|
|
|
* it provides the space for it, etc) -- we will pass that buffer
|
|
|
|
* structure back to the caller, who is responsible for managing the
|
|
|
|
* space it may have allocated as backing store for it. This second
|
|
|
|
* buffer is bodybuffer, and we only allocate the buffer itself, not
|
|
|
|
* the backing store.
|
2015-10-02 10:45:10 +02:00
|
|
|
* The third buffer is compbuffer, managed by us, that contains the
|
|
|
|
* compressed HTTP data, if compression is used.
|
|
|
|
*
|
2006-12-21 06:03:37 +00:00
|
|
|
*/
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_buffer_t headerbuffer;
|
|
|
|
isc_buffer_t compbuffer;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_buffer_t *sendbuffer;
|
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *mimetype;
|
|
|
|
unsigned int retcode;
|
|
|
|
const char *retmsg;
|
|
|
|
isc_buffer_t bodybuffer;
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_httpdfree_t *freecb;
|
2020-02-13 14:44:37 -08:00
|
|
|
void *freecb_arg;
|
2006-12-21 06:03:37 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct isc_httpdmgr {
|
2020-02-13 14:44:37 -08:00
|
|
|
unsigned int magic; /* HTTPDMGR_MAGIC */
|
|
|
|
isc_refcount_t references;
|
|
|
|
isc_mem_t *mctx;
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_nmsocket_t *sock;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdclientok_t *client_ok; /*%< client validator */
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_httpdondestroy_t *ondestroy; /*%< cleanup callback */
|
2020-02-13 14:44:37 -08:00
|
|
|
void *cb_arg; /*%< argument for the above */
|
2008-01-17 00:15:14 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
unsigned int flags;
|
|
|
|
ISC_LIST(isc_httpd_t) running; /*%< running clients */
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_mutex_t lock;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
ISC_LIST(isc_httpdurl_t) urls; /*%< urls we manage */
|
|
|
|
isc_httpdaction_t *render_404;
|
|
|
|
isc_httpdaction_t *render_500;
|
2006-12-21 06:03:37 +00:00
|
|
|
};
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_newconn(isc_nmhandle_t *, isc_result_t, void *);
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_request(isc_nmhandle_t *, isc_result_t, isc_region_t *, void *);
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_senddone(isc_nmhandle_t *, isc_result_t, void *);
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_reset(void *);
|
|
|
|
static void
|
|
|
|
httpd_put(void *);
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
httpd_addheader(isc_httpd_t *, const char *, const char *);
|
|
|
|
static isc_result_t
|
|
|
|
httpd_addheaderuint(isc_httpd_t *, const char *, int);
|
2020-02-14 08:14:03 +01:00
|
|
|
static isc_result_t
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_endheaders(isc_httpd_t *);
|
|
|
|
static isc_result_t
|
|
|
|
httpd_response(isc_httpd_t *);
|
|
|
|
|
|
|
|
static isc_result_t
|
|
|
|
process_request(isc_httpd_t *, isc_region_t *);
|
2020-02-14 08:14:03 +01:00
|
|
|
static isc_result_t
|
|
|
|
grow_headerspace(isc_httpd_t *);
|
2014-01-09 15:14:57 -08:00
|
|
|
|
|
|
|
static isc_httpdaction_t render_404;
|
|
|
|
static isc_httpdaction_t render_500;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
#if ENABLE_AFL
|
2016-05-05 11:46:11 +02:00
|
|
|
static void (*finishhook)(void) = NULL;
|
2020-01-20 12:37:57 +01:00
|
|
|
#endif /* ENABLE_AFL */
|
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
|
|
|
destroy_httpdmgr(isc_httpdmgr_t *);
|
2016-05-05 11:46:11 +02:00
|
|
|
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr_attach(isc_httpdmgr_t *, isc_httpdmgr_t **);
|
2020-02-14 08:14:03 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr_detach(isc_httpdmgr_t **);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
static inline void
|
2020-02-13 14:44:37 -08:00
|
|
|
free_buffer(isc_mem_t *mctx, isc_buffer_t *buffer) {
|
2020-01-20 12:37:57 +01:00
|
|
|
isc_region_t r;
|
2006-12-21 10:06:17 +00:00
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
isc_buffer_region(buffer, &r);
|
|
|
|
if (r.length > 0) {
|
|
|
|
isc_mem_put(mctx, r.base, r.length);
|
2020-01-17 18:24:24 +11:00
|
|
|
}
|
2020-01-20 12:37:57 +01:00
|
|
|
}
|
2020-01-17 18:24:24 +11:00
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_result_t
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_httpdmgr_create(isc_nm_t *nm, isc_mem_t *mctx, isc_sockaddr_t *addr,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdclientok_t *client_ok,
|
2008-01-17 00:15:14 +00:00
|
|
|
isc_httpdondestroy_t *ondestroy, void *cb_arg,
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_httpdmgr_t **httpdmgrp) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_httpdmgr_t *httpdmgr = NULL;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE(nm != NULL);
|
2006-12-21 06:03:37 +00:00
|
|
|
REQUIRE(mctx != NULL);
|
2015-07-10 18:42:20 +10:00
|
|
|
REQUIRE(httpdmgrp != NULL && *httpdmgrp == NULL);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2015-07-10 18:42:20 +10:00
|
|
|
httpdmgr = isc_mem_get(mctx, sizeof(isc_httpdmgr_t));
|
2020-07-09 19:36:10 -07:00
|
|
|
*httpdmgr = (isc_httpdmgr_t){ .client_ok = client_ok,
|
2020-02-12 13:59:18 +01:00
|
|
|
.ondestroy = ondestroy,
|
|
|
|
.cb_arg = cb_arg,
|
|
|
|
.render_404 = render_404,
|
|
|
|
.render_500 = render_500 };
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2018-11-16 15:33:22 +01:00
|
|
|
isc_mutex_init(&httpdmgr->lock);
|
2015-07-10 18:42:20 +10:00
|
|
|
isc_mem_attach(mctx, &httpdmgr->mctx);
|
|
|
|
|
|
|
|
ISC_LIST_INIT(httpdmgr->running);
|
|
|
|
ISC_LIST_INIT(httpdmgr->urls);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
isc_refcount_init(&httpdmgr->references, 1);
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
CHECK(isc_nm_listentcp(nm, (isc_nmiface_t *)addr, httpd_newconn,
|
|
|
|
httpdmgr, sizeof(isc_httpd_t), 5, NULL,
|
|
|
|
&httpdmgr->sock));
|
2008-01-17 00:15:14 +00:00
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
httpdmgr->magic = HTTPDMGR_MAGIC;
|
2015-07-10 18:42:20 +10:00
|
|
|
*httpdmgrp = httpdmgr;
|
2020-07-09 19:36:10 -07:00
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_SUCCESS);
|
2008-01-17 00:15:14 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
cleanup:
|
2020-01-17 18:24:24 +11:00
|
|
|
httpdmgr->magic = 0;
|
|
|
|
isc_refcount_decrement(&httpdmgr->references);
|
|
|
|
isc_refcount_destroy(&httpdmgr->references);
|
2015-07-10 18:42:20 +10:00
|
|
|
isc_mem_detach(&httpdmgr->mctx);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&httpdmgr->lock);
|
2015-07-10 18:42:20 +10:00
|
|
|
isc_mem_put(mctx, httpdmgr, sizeof(isc_httpdmgr_t));
|
2020-07-09 19:36:10 -07:00
|
|
|
|
2008-01-17 00:15:14 +00:00
|
|
|
return (result);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr_attach(isc_httpdmgr_t *source, isc_httpdmgr_t **targetp) {
|
2020-01-20 12:37:57 +01:00
|
|
|
REQUIRE(VALID_HTTPDMGR(source));
|
|
|
|
REQUIRE(targetp != NULL && *targetp == NULL);
|
|
|
|
|
|
|
|
isc_refcount_increment(&source->references);
|
|
|
|
|
|
|
|
*targetp = source;
|
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr_detach(isc_httpdmgr_t **httpdmgrp) {
|
|
|
|
isc_httpdmgr_t *httpdmgr = NULL;
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE(httpdmgrp != NULL);
|
|
|
|
REQUIRE(VALID_HTTPDMGR(*httpdmgrp));
|
|
|
|
|
|
|
|
httpdmgr = *httpdmgrp;
|
|
|
|
*httpdmgrp = NULL;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
if (isc_refcount_decrement(&httpdmgr->references) == 1) {
|
|
|
|
destroy_httpdmgr(httpdmgr);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
2020-01-20 12:37:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-02-13 14:44:37 -08:00
|
|
|
destroy_httpdmgr(isc_httpdmgr_t *httpdmgr) {
|
2020-01-20 12:37:57 +01:00
|
|
|
isc_httpdurl_t *url;
|
|
|
|
|
|
|
|
isc_refcount_destroy(&httpdmgr->references);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
LOCK(&httpdmgr->lock);
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE((httpdmgr->flags & ISC_HTTPDMGR_SHUTTINGDOWN) != 0);
|
|
|
|
REQUIRE(ISC_LIST_EMPTY(httpdmgr->running));
|
2020-01-17 18:24:24 +11:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr->magic = 0;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
if (httpdmgr->sock != NULL) {
|
|
|
|
isc_nmsocket_close(&httpdmgr->sock);
|
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Clear out the list of all actions we know about. Just free the
|
|
|
|
* memory.
|
|
|
|
*/
|
|
|
|
url = ISC_LIST_HEAD(httpdmgr->urls);
|
|
|
|
while (url != NULL) {
|
|
|
|
isc_mem_free(httpdmgr->mctx, url->url);
|
|
|
|
ISC_LIST_UNLINK(httpdmgr->urls, url, link);
|
|
|
|
isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t));
|
|
|
|
url = ISC_LIST_HEAD(httpdmgr->urls);
|
|
|
|
}
|
|
|
|
|
|
|
|
UNLOCK(&httpdmgr->lock);
|
2018-11-19 10:31:09 +00:00
|
|
|
isc_mutex_destroy(&httpdmgr->lock);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
if (httpdmgr->ondestroy != NULL) {
|
2008-01-17 00:15:14 +00:00
|
|
|
(httpdmgr->ondestroy)(httpdmgr->cb_arg);
|
2020-01-17 18:24:24 +11:00
|
|
|
}
|
|
|
|
isc_mem_putanddetach(&httpdmgr->mctx, httpdmgr, sizeof(isc_httpdmgr_t));
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
|
|
|
|
#define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
|
|
|
|
|
2016-03-02 11:04:59 +11:00
|
|
|
/*
|
|
|
|
* Look for the given header in headers.
|
|
|
|
* If value is specified look for it terminated with a character in eov.
|
|
|
|
*/
|
2018-04-17 08:29:14 -07:00
|
|
|
static bool
|
2016-03-02 11:04:59 +11:00
|
|
|
have_header(isc_httpd_t *httpd, const char *header, const char *value,
|
2020-02-13 14:44:37 -08:00
|
|
|
const char *eov) {
|
|
|
|
char *cr, *nl, *h;
|
2016-03-10 08:43:28 +11:00
|
|
|
size_t hlen, vlen = 0;
|
2016-03-02 11:04:59 +11:00
|
|
|
|
|
|
|
h = httpd->headers;
|
|
|
|
hlen = strlen(header);
|
|
|
|
if (value != NULL) {
|
|
|
|
INSIST(eov != NULL);
|
|
|
|
vlen = strlen(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
if (strncasecmp(h, header, hlen) != 0) {
|
|
|
|
/*
|
|
|
|
* Skip to next line;
|
|
|
|
*/
|
|
|
|
cr = strchr(h, '\r');
|
2020-02-13 21:48:23 +01:00
|
|
|
if (cr != NULL && cr[1] == '\n') {
|
2016-03-02 11:04:59 +11:00
|
|
|
cr++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
nl = strchr(h, '\n');
|
2016-03-05 19:50:42 -08:00
|
|
|
|
2016-03-02 11:04:59 +11:00
|
|
|
/* last header? */
|
|
|
|
h = cr;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (h == NULL || (nl != NULL && nl < h)) {
|
2016-03-02 11:04:59 +11:00
|
|
|
h = nl;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (h == NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
h++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (value == NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Skip optional leading white space.
|
|
|
|
*/
|
|
|
|
h += hlen;
|
2020-02-13 21:48:23 +01:00
|
|
|
while (*h == ' ' || *h == '\t') {
|
2016-03-02 11:04:59 +11:00
|
|
|
h++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
/*
|
|
|
|
* Terminate token search on NULL or EOL.
|
|
|
|
*/
|
|
|
|
while (*h != 0 && *h != '\r' && *h != '\n') {
|
2020-02-13 18:16:57 +01:00
|
|
|
if (strncasecmp(h, value, vlen) == 0) {
|
|
|
|
if (strchr(eov, h[vlen]) != NULL) {
|
2018-04-17 08:29:14 -07:00
|
|
|
return (true);
|
2020-02-13 21:48:23 +01:00
|
|
|
/*
|
|
|
|
* Skip to next token.
|
|
|
|
*/
|
2020-02-13 18:16:57 +01:00
|
|
|
}
|
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
/*
|
|
|
|
* Skip to next token.
|
|
|
|
*/
|
|
|
|
h += strcspn(h, eov);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (h[0] == '\r' && h[1] == '\n') {
|
2016-03-02 11:04:59 +11:00
|
|
|
h++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (h[0] != 0) {
|
2016-03-02 11:04:59 +11:00
|
|
|
h++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
}
|
2020-07-09 19:36:10 -07:00
|
|
|
|
2018-04-17 08:29:14 -07:00
|
|
|
return (false);
|
2016-03-02 11:04:59 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
static isc_result_t
|
2020-07-09 19:36:10 -07:00
|
|
|
process_request(isc_httpd_t *httpd, isc_region_t *region) {
|
|
|
|
char *s = NULL, *p = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
int delim;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
memmove(httpd->recvbuf + httpd->recvlen, region->base, region->length);
|
|
|
|
httpd->recvlen += region->length;
|
2006-12-21 06:03:37 +00:00
|
|
|
httpd->recvbuf[httpd->recvlen] = 0;
|
2014-01-09 15:14:57 -08:00
|
|
|
httpd->headers = NULL;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we don't find a blank line in our buffer, return that we need
|
|
|
|
* more data.
|
|
|
|
*/
|
|
|
|
s = strstr(httpd->recvbuf, "\r\n\r\n");
|
2016-03-02 11:04:59 +11:00
|
|
|
delim = 2;
|
2006-12-21 06:03:37 +00:00
|
|
|
if (s == NULL) {
|
|
|
|
s = strstr(httpd->recvbuf, "\n\n");
|
2016-03-02 11:04:59 +11:00
|
|
|
delim = 1;
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
if (s == NULL) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOTFOUND);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2016-03-02 11:04:59 +11:00
|
|
|
/*
|
|
|
|
* NUL terminate request at the blank line.
|
|
|
|
*/
|
|
|
|
s[delim] = 0;
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
/*
|
|
|
|
* Determine if this is a POST or GET method. Any other values will
|
|
|
|
* cause an error to be returned.
|
|
|
|
*/
|
|
|
|
if (strncmp(httpd->recvbuf, "GET ", 4) == 0) {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd->method = METHOD_GET;
|
2006-12-21 06:03:37 +00:00
|
|
|
p = httpd->recvbuf + 4;
|
|
|
|
} else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd->method = METHOD_POST;
|
2006-12-21 06:03:37 +00:00
|
|
|
p = httpd->recvbuf + 5;
|
|
|
|
} else {
|
|
|
|
return (ISC_R_RANGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* From now on, p is the start of our buffer.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract the URL.
|
|
|
|
*/
|
|
|
|
s = p;
|
|
|
|
while (LENGTHOK(s) && BUFLENOK(s) &&
|
2020-02-13 14:44:37 -08:00
|
|
|
(*s != '\n' && *s != '\r' && *s != '\0' && *s != ' '))
|
|
|
|
{
|
2006-12-21 06:03:37 +00:00
|
|
|
s++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!LENGTHOK(s)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOTFOUND);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!BUFLENOK(s)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOMEMORY);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
*s = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make the URL relative.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
if ((strncmp(p, "http:/", 6) == 0) || (strncmp(p, "https:/", 7) == 0)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
/* Skip first / */
|
2020-02-13 21:48:23 +01:00
|
|
|
while (*p != '/' && *p != 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
p++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (*p == 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_RANGE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
p++;
|
|
|
|
/* Skip second / */
|
2020-02-13 21:48:23 +01:00
|
|
|
while (*p != '/' && *p != 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
p++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (*p == 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_RANGE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
p++;
|
|
|
|
/* Find third / */
|
2020-02-13 21:48:23 +01:00
|
|
|
while (*p != '/' && *p != 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
p++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
if (*p == 0) {
|
|
|
|
p--;
|
|
|
|
*p = '/';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
httpd->url = p;
|
2016-03-02 11:04:59 +11:00
|
|
|
p = s + 1;
|
2006-12-21 06:03:37 +00:00
|
|
|
s = p;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, see if there is a ? mark in the URL. If so, this is
|
|
|
|
* part of the query string, and we will split it from the URL.
|
|
|
|
*/
|
|
|
|
httpd->querystring = strchr(httpd->url, '?');
|
|
|
|
if (httpd->querystring != NULL) {
|
|
|
|
*(httpd->querystring) = 0;
|
|
|
|
httpd->querystring++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Extract the HTTP/1.X protocol. We will bounce on anything but
|
2016-03-02 11:04:59 +11:00
|
|
|
* HTTP/1.0 or HTTP/1.1 for now.
|
2006-12-21 06:03:37 +00:00
|
|
|
*/
|
|
|
|
while (LENGTHOK(s) && BUFLENOK(s) &&
|
2020-02-13 21:48:23 +01:00
|
|
|
(*s != '\n' && *s != '\r' && *s != '\0')) {
|
2006-12-21 06:03:37 +00:00
|
|
|
s++;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!LENGTHOK(s)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOTFOUND);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
if (!BUFLENOK(s)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOMEMORY);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2016-03-02 11:04:59 +11:00
|
|
|
/*
|
|
|
|
* Check that we have the expected eol delimiter.
|
|
|
|
*/
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strncmp(s, delim == 1 ? "\n" : "\r\n", delim) != 0) {
|
2016-03-02 11:04:59 +11:00
|
|
|
return (ISC_R_RANGE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
*s = 0;
|
2020-02-12 13:59:18 +01:00
|
|
|
if ((strncmp(p, "HTTP/1.0", 8) != 0) &&
|
2020-02-13 21:48:23 +01:00
|
|
|
(strncmp(p, "HTTP/1.1", 8) != 0)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_RANGE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
httpd->protocol = p;
|
2020-02-12 13:59:18 +01:00
|
|
|
p = s + delim; /* skip past eol */
|
2006-12-21 06:03:37 +00:00
|
|
|
s = p;
|
|
|
|
|
2014-01-09 15:14:57 -08:00
|
|
|
httpd->headers = s;
|
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (have_header(httpd, "Connection:", "close", ", \t\r\n")) {
|
2006-12-21 06:03:37 +00:00
|
|
|
httpd->flags |= HTTPD_CLOSE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-13 21:48:23 +01:00
|
|
|
if (have_header(httpd, "Host:", NULL, NULL)) {
|
2006-12-21 06:03:37 +00:00
|
|
|
httpd->flags |= HTTPD_FOUNDHOST;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2015-08-20 09:55:28 +10:00
|
|
|
if (strncmp(httpd->protocol, "HTTP/1.0", 8) == 0) {
|
2020-02-13 14:44:37 -08:00
|
|
|
if (have_header(httpd, "Connection:", "Keep-Alive", ", \t\r\n"))
|
|
|
|
{
|
2015-08-20 09:55:28 +10:00
|
|
|
httpd->flags |= HTTPD_KEEPALIVE;
|
2020-02-13 21:48:23 +01:00
|
|
|
} else {
|
2015-08-20 09:55:28 +10:00
|
|
|
httpd->flags |= HTTPD_CLOSE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2015-08-20 09:55:28 +10:00
|
|
|
}
|
|
|
|
|
2015-10-02 10:45:10 +02:00
|
|
|
/*
|
|
|
|
* Check for Accept-Encoding:
|
|
|
|
*/
|
|
|
|
#ifdef HAVE_ZLIB
|
2020-02-13 21:48:23 +01:00
|
|
|
if (have_header(httpd, "Accept-Encoding:", "deflate", ";, \t\r\n")) {
|
2016-03-02 11:04:59 +11:00
|
|
|
httpd->flags |= HTTPD_ACCEPT_DEFLATE;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
|
|
|
#endif /* ifdef HAVE_ZLIB */
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
/*
|
|
|
|
* Standards compliance hooks here.
|
|
|
|
*/
|
2020-02-12 13:59:18 +01:00
|
|
|
if (strcmp(httpd->protocol, "HTTP/1.1") == 0 &&
|
2020-02-13 14:44:37 -08:00
|
|
|
((httpd->flags & HTTPD_FOUNDHOST) == 0))
|
|
|
|
{
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_RANGE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2020-01-20 12:37:57 +01:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_reset(void *arg) {
|
|
|
|
isc_httpd_t *httpd = (isc_httpd_t *)arg;
|
|
|
|
isc_httpdmgr_t *httpdmgr = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
|
|
|
httpdmgr = httpd->mgr;
|
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
|
|
|
|
|
|
|
LOCK(&httpdmgr->lock);
|
|
|
|
ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
|
|
|
|
UNLOCK(&httpdmgr->lock);
|
|
|
|
|
|
|
|
httpd->recvbuf[0] = 0;
|
|
|
|
httpd->recvlen = 0;
|
|
|
|
httpd->headers = NULL;
|
|
|
|
httpd->method = METHOD_UNKNOWN;
|
|
|
|
httpd->url = NULL;
|
|
|
|
httpd->querystring = NULL;
|
|
|
|
httpd->protocol = NULL;
|
|
|
|
httpd->flags = 0;
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_buffer_clear(&httpd->headerbuffer);
|
|
|
|
isc_buffer_clear(&httpd->compbuffer);
|
|
|
|
isc_buffer_invalidate(&httpd->bodybuffer);
|
|
|
|
|
|
|
|
httpdmgr_detach(&httpdmgr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
httpd_put(void *arg) {
|
|
|
|
isc_httpd_t *httpd = (isc_httpd_t *)arg;
|
|
|
|
isc_httpdmgr_t *httpdmgr = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
|
|
|
httpdmgr = httpd->mgr;
|
2020-01-20 12:37:57 +01:00
|
|
|
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd->magic = 0;
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
free_buffer(httpdmgr->mctx, &httpd->headerbuffer);
|
|
|
|
free_buffer(httpdmgr->mctx, &httpd->compbuffer);
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
#if ENABLE_AFL
|
|
|
|
if (finishhook != NULL) {
|
|
|
|
finishhook();
|
|
|
|
}
|
|
|
|
#endif /* ENABLE_AFL */
|
|
|
|
}
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
new_httpd(isc_httpdmgr_t *httpdmgr, isc_nmhandle_t *handle) {
|
|
|
|
isc_result_t result;
|
|
|
|
isc_httpd_t *httpd = NULL;
|
|
|
|
char *headerdata = NULL;
|
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
|
|
|
|
|
|
|
httpd = isc_nmhandle_getdata(handle);
|
|
|
|
if (httpd == NULL) {
|
|
|
|
httpd = isc_nmhandle_getextra(handle);
|
|
|
|
*httpd = (isc_httpd_t){ .handle = NULL };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (httpd->handle == NULL) {
|
|
|
|
isc_nmhandle_setdata(handle, httpd, httpd_reset, httpd_put);
|
|
|
|
} else {
|
|
|
|
INSIST(httpd->handle == handle);
|
|
|
|
}
|
|
|
|
|
|
|
|
httpdmgr_attach(httpdmgr, &httpd->mgr);
|
2020-01-20 12:37:57 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the buffer for our headers.
|
|
|
|
*/
|
|
|
|
headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW);
|
|
|
|
isc_buffer_init(&httpd->headerbuffer, headerdata, HTTP_SENDGROW);
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_buffer_clear(&httpd->headerbuffer);
|
2020-01-20 12:37:57 +01:00
|
|
|
|
|
|
|
isc_buffer_initnull(&httpd->compbuffer);
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_buffer_clear(&httpd->compbuffer);
|
|
|
|
|
2020-07-27 11:03:33 -07:00
|
|
|
isc_buffer_initnull(&httpd->bodybuffer);
|
2020-01-20 12:37:57 +01:00
|
|
|
|
|
|
|
ISC_LINK_INIT(httpd, link);
|
|
|
|
|
|
|
|
httpd->magic = HTTPD_MAGIC;
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd->state = RECV;
|
|
|
|
|
|
|
|
LOCK(&httpdmgr->lock);
|
|
|
|
ISC_LIST_APPEND(httpdmgr->running, httpd, link);
|
|
|
|
UNLOCK(&httpdmgr->lock);
|
|
|
|
|
|
|
|
isc_nmhandle_ref(handle);
|
|
|
|
result = isc_nm_read(handle, httpd_request, httpdmgr);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
isc_nmhandle_unref(handle);
|
|
|
|
}
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
return (result);
|
2020-01-20 12:37:57 +01:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_newconn(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
|
|
|
isc_httpdmgr_t *httpdmgr = (isc_httpdmgr_t *)arg;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_sockaddr_t peeraddr;
|
2020-01-20 12:37:57 +01:00
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
if ((httpdmgr->flags & ISC_HTTPDMGR_SHUTTINGDOWN) != 0) {
|
|
|
|
return (ISC_R_CANCELED);
|
|
|
|
} else if (result == ISC_R_CANCELED) {
|
|
|
|
isc_httpdmgr_shutdown(&httpdmgr);
|
|
|
|
return (result);
|
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
|
|
|
return (result);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
peeraddr = isc_nmhandle_peeraddr(handle);
|
2008-01-17 00:15:14 +00:00
|
|
|
if (httpdmgr->client_ok != NULL &&
|
2020-02-13 14:44:37 -08:00
|
|
|
!(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg))
|
|
|
|
{
|
2020-07-09 19:36:10 -07:00
|
|
|
return (ISC_R_FAILURE);
|
2020-01-20 12:37:57 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
return (new_httpd(httpdmgr, handle));
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-12 13:59:18 +01:00
|
|
|
render_404(const char *url, isc_httpdurl_t *urlinfo, const char *querystring,
|
|
|
|
const char *headers, void *arg, unsigned int *retcode,
|
|
|
|
const char **retmsg, const char **mimetype, isc_buffer_t *b,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdfree_t **freecb, void **freecb_args) {
|
2015-08-20 09:55:28 +10:00
|
|
|
static char msg[] = "No such URL.\r\n";
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
UNUSED(url);
|
2014-01-09 15:14:57 -08:00
|
|
|
UNUSED(urlinfo);
|
2006-12-21 06:03:37 +00:00
|
|
|
UNUSED(querystring);
|
2014-01-09 15:14:57 -08:00
|
|
|
UNUSED(headers);
|
2006-12-21 06:03:37 +00:00
|
|
|
UNUSED(arg);
|
|
|
|
|
|
|
|
*retcode = 404;
|
|
|
|
*retmsg = "No such URL";
|
|
|
|
*mimetype = "text/plain";
|
|
|
|
isc_buffer_reinit(b, msg, strlen(msg));
|
|
|
|
isc_buffer_add(b, strlen(msg));
|
|
|
|
*freecb = NULL;
|
|
|
|
*freecb_args = NULL;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2010-02-04 00:57:25 +00:00
|
|
|
static isc_result_t
|
2020-02-12 13:59:18 +01:00
|
|
|
render_500(const char *url, isc_httpdurl_t *urlinfo, const char *querystring,
|
|
|
|
const char *headers, void *arg, unsigned int *retcode,
|
|
|
|
const char **retmsg, const char **mimetype, isc_buffer_t *b,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdfree_t **freecb, void **freecb_args) {
|
2015-08-20 09:55:28 +10:00
|
|
|
static char msg[] = "Internal server failure.\r\n";
|
2010-02-04 00:57:25 +00:00
|
|
|
|
|
|
|
UNUSED(url);
|
2014-01-09 15:14:57 -08:00
|
|
|
UNUSED(urlinfo);
|
2010-02-04 00:57:25 +00:00
|
|
|
UNUSED(querystring);
|
2014-01-09 15:14:57 -08:00
|
|
|
UNUSED(headers);
|
2010-02-04 00:57:25 +00:00
|
|
|
UNUSED(arg);
|
|
|
|
|
|
|
|
*retcode = 500;
|
|
|
|
*retmsg = "Internal server failure";
|
|
|
|
*mimetype = "text/plain";
|
|
|
|
isc_buffer_reinit(b, msg, strlen(msg));
|
|
|
|
isc_buffer_add(b, strlen(msg));
|
|
|
|
*freecb = NULL;
|
|
|
|
*freecb_args = NULL;
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2015-10-02 10:45:10 +02:00
|
|
|
#ifdef HAVE_ZLIB
|
|
|
|
/*%<
|
|
|
|
* Reallocates compbuffer to size, does nothing if compbuffer is already
|
|
|
|
* larger than size.
|
|
|
|
*
|
|
|
|
* Requires:
|
|
|
|
*\li httpd a valid isc_httpd_t object
|
|
|
|
*
|
|
|
|
* Returns:
|
|
|
|
*\li #ISC_R_SUCCESS -- all is well.
|
|
|
|
*\li #ISC_R_NOMEMORY -- not enough memory to extend buffer
|
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
alloc_compspace(isc_httpd_t *httpd, unsigned int size) {
|
|
|
|
char *newspace;
|
2015-10-02 10:45:10 +02:00
|
|
|
isc_region_t r;
|
|
|
|
|
|
|
|
isc_buffer_region(&httpd->compbuffer, &r);
|
|
|
|
if (size < r.length) {
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
newspace = isc_mem_get(httpd->mgr->mctx, size);
|
|
|
|
isc_buffer_reinit(&httpd->compbuffer, newspace, size);
|
|
|
|
|
|
|
|
if (r.base != NULL) {
|
|
|
|
isc_mem_put(httpd->mgr->mctx, r.base, r.length);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*%<
|
|
|
|
* Tries to compress httpd->bodybuffer to httpd->compbuffer, extending it
|
|
|
|
* if necessary.
|
|
|
|
*
|
|
|
|
* Requires:
|
|
|
|
*\li httpd a valid isc_httpd_t object
|
|
|
|
*
|
|
|
|
* Returns:
|
2015-10-02 18:47:33 -07:00
|
|
|
*\li #ISC_R_SUCCESS -- all is well.
|
|
|
|
*\li #ISC_R_NOMEMORY -- not enough memory to compress data
|
|
|
|
*\li #ISC_R_FAILURE -- error during compression or compressed
|
|
|
|
* data would be larger than input data
|
2015-10-02 10:45:10 +02:00
|
|
|
*/
|
|
|
|
static isc_result_t
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_compress(isc_httpd_t *httpd) {
|
2020-02-13 14:44:37 -08:00
|
|
|
z_stream zstr;
|
2015-10-02 10:45:10 +02:00
|
|
|
isc_region_t r;
|
|
|
|
isc_result_t result;
|
2020-02-13 14:44:37 -08:00
|
|
|
int ret;
|
|
|
|
int inputlen;
|
2015-10-02 10:45:10 +02:00
|
|
|
|
|
|
|
inputlen = isc_buffer_usedlength(&httpd->bodybuffer);
|
|
|
|
result = alloc_compspace(httpd, inputlen);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-02-13 21:48:23 +01:00
|
|
|
return (result);
|
2015-10-02 10:45:10 +02:00
|
|
|
}
|
|
|
|
isc_buffer_region(&httpd->compbuffer, &r);
|
|
|
|
|
2015-10-02 18:47:33 -07:00
|
|
|
/*
|
|
|
|
* We're setting output buffer size to input size so it fails if the
|
2015-10-02 10:45:10 +02:00
|
|
|
* compressed data size would be bigger than the input size.
|
|
|
|
*/
|
2015-10-02 18:47:33 -07:00
|
|
|
memset(&zstr, 0, sizeof(zstr));
|
2020-02-12 13:59:18 +01:00
|
|
|
zstr.total_in = zstr.avail_in = zstr.total_out = zstr.avail_out =
|
|
|
|
inputlen;
|
2015-10-02 10:45:10 +02:00
|
|
|
|
|
|
|
zstr.next_in = isc_buffer_base(&httpd->bodybuffer);
|
|
|
|
zstr.next_out = r.base;
|
|
|
|
|
|
|
|
ret = deflateInit(&zstr, Z_DEFAULT_COMPRESSION);
|
|
|
|
if (ret == Z_OK) {
|
|
|
|
ret = deflate(&zstr, Z_FINISH);
|
|
|
|
}
|
|
|
|
deflateEnd(&zstr);
|
|
|
|
if (ret == Z_STREAM_END) {
|
|
|
|
isc_buffer_add(&httpd->compbuffer, inputlen - zstr.avail_out);
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
} else {
|
|
|
|
return (ISC_R_FAILURE);
|
|
|
|
}
|
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef HAVE_ZLIB */
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_request(isc_nmhandle_t *handle, isc_result_t eresult,
|
|
|
|
isc_region_t *region, void *arg) {
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_result_t result;
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_httpd_t *httpd = NULL;
|
|
|
|
isc_httpdmgr_t *mgr = (isc_httpdmgr_t *)arg;
|
|
|
|
isc_buffer_t *databuffer = NULL;
|
|
|
|
isc_httpdurl_t *url = NULL;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_time_t now;
|
|
|
|
isc_region_t r;
|
|
|
|
bool is_compressed = false;
|
|
|
|
char datebuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd = isc_nmhandle_getdata(handle);
|
2020-01-20 12:37:57 +01:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE(httpd->state == RECV);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
if (eresult != ISC_R_SUCCESS) {
|
|
|
|
goto done;
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
result = process_request(httpd, region);
|
2006-12-21 06:03:37 +00:00
|
|
|
if (result == ISC_R_NOTFOUND) {
|
2020-07-09 19:36:10 -07:00
|
|
|
if (httpd->recvlen < HTTP_RECVLEN - 1) {
|
|
|
|
/* don't unref, continue reading */
|
|
|
|
return;
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
2020-07-09 19:36:10 -07:00
|
|
|
goto done;
|
2006-12-21 06:03:37 +00:00
|
|
|
} else if (result != ISC_R_SUCCESS) {
|
2020-07-09 19:36:10 -07:00
|
|
|
goto done;
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_buffer_initnull(&httpd->bodybuffer);
|
|
|
|
isc_time_now(&now);
|
|
|
|
isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
|
2020-07-09 19:36:10 -07:00
|
|
|
|
|
|
|
LOCK(&mgr->lock);
|
|
|
|
url = ISC_LIST_HEAD(mgr->urls);
|
2006-12-21 06:03:37 +00:00
|
|
|
while (url != NULL) {
|
2020-02-13 21:48:23 +01:00
|
|
|
if (strcmp(httpd->url, url->url) == 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
break;
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
url = ISC_LIST_NEXT(url, link);
|
|
|
|
}
|
2020-07-09 19:36:10 -07:00
|
|
|
UNLOCK(&mgr->lock);
|
2020-01-17 18:24:24 +11:00
|
|
|
|
|
|
|
if (url == NULL) {
|
2020-07-09 19:36:10 -07:00
|
|
|
result = mgr->render_404(
|
2020-02-12 13:59:18 +01:00
|
|
|
httpd->url, NULL, httpd->querystring, NULL, NULL,
|
|
|
|
&httpd->retcode, &httpd->retmsg, &httpd->mimetype,
|
|
|
|
&httpd->bodybuffer, &httpd->freecb, &httpd->freecb_arg);
|
2020-01-17 18:24:24 +11:00
|
|
|
} else {
|
2020-02-12 13:59:18 +01:00
|
|
|
result = url->action(httpd->url, url, httpd->querystring,
|
|
|
|
httpd->headers, url->action_arg,
|
2006-12-21 06:03:37 +00:00
|
|
|
&httpd->retcode, &httpd->retmsg,
|
|
|
|
&httpd->mimetype, &httpd->bodybuffer,
|
|
|
|
&httpd->freecb, &httpd->freecb_arg);
|
2020-01-17 18:24:24 +11:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2020-07-09 19:36:10 -07:00
|
|
|
result = mgr->render_500(
|
2020-02-12 13:59:18 +01:00
|
|
|
httpd->url, url, httpd->querystring, NULL, NULL,
|
|
|
|
&httpd->retcode, &httpd->retmsg, &httpd->mimetype,
|
|
|
|
&httpd->bodybuffer, &httpd->freecb, &httpd->freecb_arg);
|
2011-03-11 06:11:27 +00:00
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
2008-01-18 23:46:58 +00:00
|
|
|
|
2015-10-02 10:45:10 +02:00
|
|
|
#ifdef HAVE_ZLIB
|
2018-10-11 11:57:57 +02:00
|
|
|
if ((httpd->flags & HTTPD_ACCEPT_DEFLATE) != 0) {
|
2020-07-09 19:36:10 -07:00
|
|
|
result = httpd_compress(httpd);
|
2020-02-12 13:59:18 +01:00
|
|
|
if (result == ISC_R_SUCCESS) {
|
|
|
|
is_compressed = true;
|
|
|
|
}
|
2015-10-02 10:45:10 +02:00
|
|
|
}
|
2020-02-13 21:48:23 +01:00
|
|
|
#endif /* ifdef HAVE_ZLIB */
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_response(httpd);
|
2020-01-17 18:24:24 +11:00
|
|
|
if ((httpd->flags & HTTPD_KEEPALIVE) != 0) {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Connection", "Keep-Alive");
|
2020-01-17 18:24:24 +11:00
|
|
|
}
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Content-Type", httpd->mimetype);
|
|
|
|
httpd_addheader(httpd, "Date", datebuf);
|
|
|
|
httpd_addheader(httpd, "Expires", datebuf);
|
2014-01-09 15:14:57 -08:00
|
|
|
|
|
|
|
if (url != NULL && url->isstatic) {
|
2015-02-05 17:18:15 -08:00
|
|
|
char loadbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
|
2020-02-12 13:59:18 +01:00
|
|
|
isc_time_formathttptimestamp(&url->loadtime, loadbuf,
|
|
|
|
sizeof(loadbuf));
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Last-Modified", loadbuf);
|
|
|
|
httpd_addheader(httpd, "Cache-Control: public", NULL);
|
2014-01-09 15:14:57 -08:00
|
|
|
} else {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Last-Modified", datebuf);
|
|
|
|
httpd_addheader(httpd, "Pragma: no-cache", NULL);
|
|
|
|
httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
|
2014-01-09 15:14:57 -08:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Server: libisc", NULL);
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2020-03-30 13:47:58 -07:00
|
|
|
if (is_compressed) {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheader(httpd, "Content-Encoding", "deflate");
|
|
|
|
httpd_addheaderuint(httpd, "Content-Length",
|
|
|
|
isc_buffer_usedlength(&httpd->compbuffer));
|
2015-10-02 10:45:10 +02:00
|
|
|
} else {
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_addheaderuint(httpd, "Content-Length",
|
|
|
|
isc_buffer_usedlength(&httpd->bodybuffer));
|
2015-10-02 10:45:10 +02:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_endheaders(httpd); /* done */
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2018-10-31 13:46:52 +01:00
|
|
|
/*
|
|
|
|
* Append either the compressed or the non-compressed response body to
|
|
|
|
* the response headers and store the result in httpd->sendbuffer.
|
|
|
|
*/
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_buffer_dup(mgr->mctx, &httpd->sendbuffer, &httpd->headerbuffer);
|
2018-10-31 13:46:52 +01:00
|
|
|
isc_buffer_setautorealloc(httpd->sendbuffer, true);
|
|
|
|
databuffer = (is_compressed ? &httpd->compbuffer : &httpd->bodybuffer);
|
|
|
|
isc_buffer_usedregion(databuffer, &r);
|
|
|
|
result = isc_buffer_copyregion(httpd->sendbuffer, &r);
|
|
|
|
RUNTIME_CHECK(result == ISC_R_SUCCESS);
|
2020-07-09 19:36:10 -07:00
|
|
|
|
2018-10-31 13:46:52 +01:00
|
|
|
/*
|
|
|
|
* Determine total response size.
|
|
|
|
*/
|
2018-10-26 19:07:41 +00:00
|
|
|
isc_buffer_usedregion(httpd->sendbuffer, &r);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_nm_pauseread(handle);
|
|
|
|
httpd->state = SEND;
|
|
|
|
|
|
|
|
isc_nmhandle_ref(handle);
|
|
|
|
result = isc_nm_send(handle, &r, httpd_senddone, httpd);
|
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
isc_nm_resumeread(handle);
|
|
|
|
isc_nmhandle_unref(handle);
|
|
|
|
|
|
|
|
httpd->state = RECV;
|
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
return;
|
|
|
|
done:
|
|
|
|
isc_nmhandle_unref(handle);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_httpdmgr_t *httpdmgr;
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpd_t *httpd;
|
2020-01-17 18:24:24 +11:00
|
|
|
|
|
|
|
REQUIRE(httpdmgrp != NULL);
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE(VALID_HTTPDMGR(*httpdmgrp));
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
httpdmgr = *httpdmgrp;
|
|
|
|
*httpdmgrp = NULL;
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_nm_stoplistening(httpdmgr->sock);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
LOCK(&httpdmgr->lock);
|
|
|
|
httpdmgr->flags |= ISC_HTTPDMGR_SHUTTINGDOWN;
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
httpd = ISC_LIST_HEAD(httpdmgr->running);
|
|
|
|
while (httpd != NULL) {
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_nmhandle_unref(httpd->handle);
|
2006-12-21 06:03:37 +00:00
|
|
|
httpd = ISC_LIST_NEXT(httpd, link);
|
|
|
|
}
|
|
|
|
UNLOCK(&httpdmgr->lock);
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpdmgr_detach(&httpdmgr);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static isc_result_t
|
2020-02-13 14:44:37 -08:00
|
|
|
grow_headerspace(isc_httpd_t *httpd) {
|
2020-07-09 19:36:10 -07:00
|
|
|
char *newspace = NULL;
|
2006-12-21 06:03:37 +00:00
|
|
|
unsigned int newlen;
|
|
|
|
isc_region_t r;
|
|
|
|
|
2015-10-02 10:45:10 +02:00
|
|
|
isc_buffer_region(&httpd->headerbuffer, &r);
|
|
|
|
newlen = r.length + HTTP_SENDGROW;
|
2020-02-13 21:48:23 +01:00
|
|
|
if (newlen > HTTP_SEND_MAXLEN) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (ISC_R_NOSPACE);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
newspace = isc_mem_get(httpd->mgr->mctx, newlen);
|
2015-10-02 10:45:10 +02:00
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen);
|
|
|
|
|
|
|
|
isc_mem_put(httpd->mgr->mctx, r.base, r.length);
|
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_response(isc_httpd_t *httpd) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_result_t result;
|
|
|
|
unsigned int needlen;
|
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
needlen = strlen(httpd->protocol) + 1; /* protocol + space */
|
2020-02-12 13:59:18 +01:00
|
|
|
needlen += 3 + 1; /* room for response code, always 3 bytes */
|
|
|
|
needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2011-02-21 05:55:09 +00:00
|
|
|
while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
|
2006-12-21 06:03:37 +00:00
|
|
|
result = grow_headerspace(httpd);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 11:43:07 +02:00
|
|
|
return (isc_buffer_printf(&httpd->headerbuffer, "%s %03u %s\r\n",
|
2020-02-12 13:59:18 +01:00
|
|
|
httpd->protocol, httpd->retcode,
|
|
|
|
httpd->retmsg));
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_addheader(isc_httpd_t *httpd, const char *name, const char *val) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_result_t result;
|
|
|
|
unsigned int needlen;
|
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
needlen = strlen(name); /* name itself */
|
2020-01-17 18:24:24 +11:00
|
|
|
if (val != NULL) {
|
2006-12-21 06:03:37 +00:00
|
|
|
needlen += 2 + strlen(val); /* :<space> and val */
|
2020-01-17 18:24:24 +11:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
needlen += 2; /* CRLF */
|
|
|
|
|
2011-02-21 05:55:09 +00:00
|
|
|
while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
|
2006-12-21 06:03:37 +00:00
|
|
|
result = grow_headerspace(httpd);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 11:43:07 +02:00
|
|
|
if (val != NULL) {
|
|
|
|
return (isc_buffer_printf(&httpd->headerbuffer, "%s: %s\r\n",
|
2020-02-12 13:59:18 +01:00
|
|
|
name, val));
|
2017-10-09 11:43:07 +02:00
|
|
|
} else {
|
|
|
|
return (isc_buffer_printf(&httpd->headerbuffer, "%s\r\n",
|
2020-02-12 13:59:18 +01:00
|
|
|
name));
|
2017-10-09 11:43:07 +02:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_endheaders(isc_httpd_t *httpd) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_result_t result;
|
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
2011-02-21 05:55:09 +00:00
|
|
|
while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
|
2006-12-21 06:03:37 +00:00
|
|
|
result = grow_headerspace(httpd);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 11:43:07 +02:00
|
|
|
return (isc_buffer_printf(&httpd->headerbuffer, "\r\n"));
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
static isc_result_t
|
|
|
|
httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_result_t result;
|
|
|
|
unsigned int needlen;
|
2020-02-13 14:44:37 -08:00
|
|
|
char buf[sizeof "18446744073709551616"];
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
|
|
|
|
2017-10-03 14:54:19 +11:00
|
|
|
snprintf(buf, sizeof(buf), "%d", val);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2020-02-12 13:59:18 +01:00
|
|
|
needlen = strlen(name); /* name itself */
|
2006-12-21 06:03:37 +00:00
|
|
|
needlen += 2 + strlen(buf); /* :<space> and val */
|
2020-02-12 13:59:18 +01:00
|
|
|
needlen += 2; /* CRLF */
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2011-02-21 05:55:09 +00:00
|
|
|
while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
|
2006-12-21 06:03:37 +00:00
|
|
|
result = grow_headerspace(httpd);
|
2020-02-13 21:48:23 +01:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
2006-12-21 06:03:37 +00:00
|
|
|
return (result);
|
2020-02-13 21:48:23 +01:00
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2017-10-09 11:43:07 +02:00
|
|
|
return (isc_buffer_printf(&httpd->headerbuffer, "%s: %s\r\n", name,
|
2020-02-12 13:59:18 +01:00
|
|
|
buf));
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd_senddone(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
|
|
|
|
isc_httpd_t *httpd = (isc_httpd_t *)arg;
|
2020-01-17 18:24:24 +11:00
|
|
|
|
|
|
|
REQUIRE(VALID_HTTPD(httpd));
|
2020-07-09 19:36:10 -07:00
|
|
|
REQUIRE(httpd->state == SEND);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
2018-10-26 19:07:41 +00:00
|
|
|
isc_buffer_free(&httpd->sendbuffer);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We will always want to clean up our receive buffer, even if we
|
|
|
|
* got an error on send or we are shutting down.
|
|
|
|
*/
|
|
|
|
if (httpd->freecb != NULL) {
|
|
|
|
isc_buffer_t *b = NULL;
|
2013-03-13 14:24:50 -07:00
|
|
|
if (isc_buffer_length(&httpd->bodybuffer) > 0) {
|
2006-12-21 06:03:37 +00:00
|
|
|
b = &httpd->bodybuffer;
|
2013-03-13 14:24:50 -07:00
|
|
|
httpd->freecb(b, httpd->freecb_arg);
|
|
|
|
}
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
if (result != ISC_R_SUCCESS) {
|
|
|
|
return;
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 19:36:10 -07:00
|
|
|
httpd->state = RECV;
|
|
|
|
isc_nm_resumeread(handle);
|
|
|
|
isc_nmhandle_unref(handle);
|
2006-12-21 06:03:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t
|
2020-07-09 19:36:10 -07:00
|
|
|
isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, bool isstatic,
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpdaction_t *func, void *arg) {
|
2006-12-21 06:03:37 +00:00
|
|
|
isc_httpdurl_t *item;
|
|
|
|
|
2020-01-17 18:24:24 +11:00
|
|
|
REQUIRE(VALID_HTTPDMGR(httpdmgr));
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
if (url == NULL) {
|
|
|
|
httpdmgr->render_404 = func;
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t));
|
|
|
|
|
|
|
|
item->url = isc_mem_strdup(httpdmgr->mctx, url);
|
|
|
|
|
|
|
|
item->action = func;
|
|
|
|
item->action_arg = arg;
|
2014-01-09 15:14:57 -08:00
|
|
|
item->isstatic = isstatic;
|
|
|
|
isc_time_now(&item->loadtime);
|
|
|
|
|
2006-12-21 06:03:37 +00:00
|
|
|
ISC_LINK_INIT(item, link);
|
2020-01-17 18:24:24 +11:00
|
|
|
|
|
|
|
LOCK(&httpdmgr->lock);
|
2006-12-21 06:03:37 +00:00
|
|
|
ISC_LIST_APPEND(httpdmgr->urls, item, link);
|
2020-01-17 18:24:24 +11:00
|
|
|
UNLOCK(&httpdmgr->lock);
|
2006-12-21 06:03:37 +00:00
|
|
|
|
|
|
|
return (ISC_R_SUCCESS);
|
|
|
|
}
|
2016-05-05 11:46:11 +02:00
|
|
|
|
|
|
|
void
|
2020-02-13 14:44:37 -08:00
|
|
|
isc_httpd_setfinishhook(void (*fn)(void)) {
|
2020-01-20 12:37:57 +01:00
|
|
|
#if ENABLE_AFL
|
2016-05-05 11:46:11 +02:00
|
|
|
finishhook = fn;
|
2020-02-12 13:59:18 +01:00
|
|
|
#else /* ENABLE_AFL */
|
2020-01-20 12:37:57 +01:00
|
|
|
UNUSED(fn);
|
|
|
|
#endif /* ENABLE_AFL */
|
2016-05-05 11:46:11 +02:00
|
|
|
}
|