Rewrite isc_httpd using picohttpparser and isc_url_parse

Rewrite the isc_httpd to be more robust.

1. Replace the hand-crafted HTTP request parser with picohttpparser for
   parsing the whole HTTP/1.0 and HTTP/1.1 requests.  Limit the number
   of allowed headers to 10 (arbitrary number).

2. Replace the hand-crafted URL parser with isc_url_parse for parsing
   the URL from the HTTP request.

3. Increase the receive buffer to match the isc_netmgr buffers, so we
   can at least receive two full isc_nm_read()s.  This makes the
   truncation processing much simpler.

4. Process the received buffer from single isc_nm_read() in a single
   loop and schedule the sends to be independent of each other.

The first two changes makes the code simpler and rely on already
existing libraries that we already had (isc_url based on nodejs) or are
used elsewhere (picohttpparser).

The second two changes remove the artificial "truncation" limit on
parsing multiple request.  Now only a request that has too many
headers (currently 10) or is too big (so, the receive buffer fills up
without reaching end of the request) will end the connection.

We can be benevolent here with the limites, because the statschannel
channel is by definition private and access must be allowed only to
administrators of the server.  There are no timers, no rate-limiting, no
upper limit on the number of requests that can be served, etc.

(cherry picked from commit beecde7120)
This commit is contained in:
Ondřej Surý
2022-10-06 12:56:25 +02:00
parent 944ddd0fb2
commit 067502a16e
6 changed files with 587 additions and 803 deletions

View File

@@ -23,28 +23,20 @@
#include <isc/task.h>
#include <isc/time.h>
#include <isc/types.h>
/*%
* HTTP urls. These are the URLs we manage, and the function to call to
* provide the data for it. We pass in the base url (so the same function
* can handle multiple requests), and a structure to fill in to return a
* result to the client. We also pass in a pointer to be filled in for
* the data cleanup function.
*/
struct isc_httpdurl {
char *url;
isc_httpdaction_t *action;
void *action_arg;
bool isstatic;
isc_time_t loadtime;
ISC_LINK(isc_httpdurl_t) link;
};
#include <isc/url.h>
#define HTTPD_EVENTCLASS ISC_EVENTCLASS(4300)
#define HTTPD_SHUTDOWN (HTTPD_EVENTCLASS + 0x0001)
#define ISC_HTTPDMGR_SHUTTINGDOWN 0x00000001
typedef isc_result_t(isc_httpdaction_t)(
const isc_httpd_t *httpd, const isc_httpdurl_t *urlinfo, void *arg,
unsigned int *retcode, const char **retmsg, const char **mimetype,
isc_buffer_t *body, isc_httpdfree_t **freecb, void **freecb_args);
typedef bool(isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
isc_result_t
isc_httpdmgr_create(isc_nm_t *nm, isc_mem_t *mctx, isc_sockaddr_t *addr,
isc_httpdclientok_t *client_ok,
@@ -60,3 +52,12 @@ isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url, bool isstatic,
void
isc_httpd_setfinishhook(void (*fn)(void));
bool
isc_httpdurl_isstatic(const isc_httpdurl_t *url);
const isc_time_t *
isc_httpdurl_loadtime(const isc_httpdurl_t *url);
const isc_time_t *
isc_httpd_if_modified_since(const isc_httpd_t *httpd);

View File

@@ -95,14 +95,6 @@ typedef struct isc_nm_http_endpoints isc_nm_http_endpoints_t;
typedef void (*isc_taskaction_t)(isc_task_t *, isc_event_t *);
/* The following cannot be listed alphabetically due to forward reference */
typedef isc_result_t(isc_httpdaction_t)(
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 *body,
isc_httpdfree_t **freecb, void **freecb_args);
typedef bool(isc_httpdclientok_t)(const isc_sockaddr_t *, void *);
/*% Resource */
typedef enum {
isc_resource_coresize = 1,

View File

@@ -36,6 +36,7 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <isc/result.h>