mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 04:29:02 -04:00
HTTP improvements.
Introduce an on_headers callback for routes, allowing one to inspect the headers before the request is processed further. Additionall, Add a new way of obtaining HTTP headers. Much like http_argument_get_*() functions, these new APIs allow you to fetch the data of an HTTP header as a specified C type. The new APIs are: * http_request_header_int16() * http_request_header_uint16() * http_request_header_int32() * http_request_header_uint32() * http_request_header_int64() * http_request_header_uint64() * http_request_header_float() * http_request_header_double() Should make it easier to operate in HTTP header data in a safe way. No need to always roll your own string to int conversion functions.
This commit is contained in:
parent
e98a4ddab5
commit
f5a58368b7
@ -119,7 +119,7 @@ struct http_arg {
|
||||
do { \
|
||||
int err; \
|
||||
type nval; \
|
||||
nval = (type)kore_strtonum64(q->s_value, sign, &err); \
|
||||
nval = (type)kore_strtonum64(data, sign, &err); \
|
||||
if (err != KORE_RESULT_OK) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
COPY_ARG_TYPE(nval, type); \
|
||||
@ -129,7 +129,7 @@ struct http_arg {
|
||||
do { \
|
||||
int err; \
|
||||
type nval; \
|
||||
nval = kore_strtodouble(q->s_value, min, max, &err); \
|
||||
nval = kore_strtodouble(data, min, max, &err); \
|
||||
if (err != KORE_RESULT_OK) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
COPY_ARG_TYPE(nval, type); \
|
||||
@ -139,7 +139,7 @@ struct http_arg {
|
||||
do { \
|
||||
int err; \
|
||||
int64_t nval; \
|
||||
nval = kore_strtonum(q->s_value, 10, min, max, &err); \
|
||||
nval = kore_strtonum(data, 10, min, max, &err); \
|
||||
if (err != KORE_RESULT_OK) \
|
||||
return (KORE_RESULT_ERROR); \
|
||||
COPY_ARG_TYPE(nval, type); \
|
||||
@ -159,38 +159,62 @@ struct http_arg {
|
||||
COPY_ARG_INT(min, max, type); \
|
||||
} while (0)
|
||||
|
||||
#define http_argument_type(r, n, so, no, t) \
|
||||
http_argument_get(r, n, so, no, t)
|
||||
|
||||
#define http_argument_get_string(r, n, o) \
|
||||
http_argument_type(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
|
||||
http_argument_get(r, n, (void **)o, NULL, HTTP_ARG_TYPE_STRING)
|
||||
|
||||
#define http_argument_get_byte(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
|
||||
#define http_argument_get_byte(r, n, o) \
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
|
||||
|
||||
#define http_argument_get_uint16(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
|
||||
|
||||
#define http_argument_get_int16(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
|
||||
|
||||
#define http_argument_get_uint32(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
|
||||
|
||||
#define http_argument_get_int32(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
|
||||
|
||||
#define http_argument_get_uint64(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
|
||||
|
||||
#define http_argument_get_int64(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
|
||||
|
||||
#define http_argument_get_float(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
|
||||
|
||||
#define http_argument_get_double(r, n, o) \
|
||||
http_argument_type(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
|
||||
http_argument_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
|
||||
|
||||
#define http_request_header_byte(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_BYTE)
|
||||
|
||||
#define http_request_header_uint16(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT16)
|
||||
|
||||
#define http_request_header_int16(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT16)
|
||||
|
||||
#define http_request_header_uint32(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT32)
|
||||
|
||||
#define http_request_header_int32(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT32)
|
||||
|
||||
#define http_request_header_uint64(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_UINT64)
|
||||
|
||||
#define http_request_header_int64(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_INT64)
|
||||
|
||||
#define http_request_header_float(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_FLOAT)
|
||||
|
||||
#define http_request_header_double(r, n, o) \
|
||||
http_request_header_get(r, n, NULL, o, HTTP_ARG_TYPE_DOUBLE)
|
||||
|
||||
struct http_file {
|
||||
char *name;
|
||||
@ -262,9 +286,9 @@ struct http_request {
|
||||
struct kore_buf *http_body;
|
||||
int http_body_fd;
|
||||
char *http_body_path;
|
||||
size_t http_body_length;
|
||||
size_t http_body_offset;
|
||||
size_t content_length;
|
||||
u_int64_t http_body_length;
|
||||
u_int64_t http_body_offset;
|
||||
u_int64_t content_length;
|
||||
void *hdlr_extra;
|
||||
size_t state_len;
|
||||
char *query_string;
|
||||
@ -400,6 +424,8 @@ void http_populate_multipart_form(struct http_request *);
|
||||
void http_populate_cookies(struct http_request *);
|
||||
int http_argument_get(struct http_request *,
|
||||
const char *, void **, void *, int);
|
||||
int http_request_header_get(struct http_request *,
|
||||
const char *, void **, void *, int);
|
||||
|
||||
void http_file_rewind(struct http_file *);
|
||||
ssize_t http_file_read(struct http_file *, void *, size_t);
|
||||
|
@ -320,11 +320,14 @@ struct kore_route {
|
||||
char *func;
|
||||
int type;
|
||||
int errors;
|
||||
int methods;
|
||||
regex_t rctx;
|
||||
struct kore_domain *dom;
|
||||
struct kore_runtime_call *rcall;
|
||||
struct kore_auth *auth;
|
||||
int methods;
|
||||
struct kore_runtime_call *rcall;
|
||||
struct kore_runtime_call *on_headers;
|
||||
struct kore_runtime_call *on_body_chunk;
|
||||
|
||||
TAILQ_HEAD(, kore_route_params) params;
|
||||
TAILQ_ENTRY(kore_route) list;
|
||||
};
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "kore.h"
|
||||
@ -174,7 +175,7 @@ kore_accesslog(struct http_request *req)
|
||||
worker->lb.offset += sizeof(*hdr);
|
||||
|
||||
len = snprintf(worker->lb.buf + worker->lb.offset, avail,
|
||||
"%s - %s [%s] \"%s %s %s\" %d %zu \"%s\" \"%s\"\n",
|
||||
"%s - %s [%s] \"%s %s %s\" %d %" PRIu64" \"%s\" \"%s\"\n",
|
||||
addr, cn, tbuf, method, req->path, http_version,
|
||||
req->status, req->content_length, referer, req->agent);
|
||||
if (len == -1)
|
||||
|
44
src/config.c
44
src/config.c
@ -109,8 +109,10 @@ static int configure_client_verify_depth(char *);
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int configure_route(char *);
|
||||
static int configure_route_handler(char *);
|
||||
static int configure_route_methods(char *);
|
||||
static int configure_route_handler(char *);
|
||||
static int configure_route_on_headers(char *);
|
||||
static int configure_route_on_body_chunk(char *);
|
||||
static int configure_filemap(char *);
|
||||
static int configure_return(char *);
|
||||
static int configure_redirect(char *);
|
||||
@ -191,6 +193,8 @@ static struct {
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
{ "route", configure_route },
|
||||
{ "handler", configure_route_handler },
|
||||
{ "on_headers", configure_route_on_headers },
|
||||
{ "on_body_chunk", configure_route_on_body_chunk },
|
||||
{ "methods", configure_route_methods },
|
||||
{ "filemap", configure_filemap },
|
||||
{ "redirect", configure_redirect },
|
||||
@ -1155,6 +1159,44 @@ configure_route_handler(char *name)
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_route_on_headers(char *name)
|
||||
{
|
||||
if (current_route == NULL) {
|
||||
kore_log(LOG_ERR,
|
||||
"on_header keyword not inside of route context");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if ((current_route->on_headers = kore_runtime_getcall(name)) == NULL) {
|
||||
kore_log(LOG_ERR, "on_headers callback '%s' for '%s' not found",
|
||||
name, current_route->path);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_route_on_body_chunk(char *name)
|
||||
{
|
||||
if (current_route == NULL) {
|
||||
kore_log(LOG_ERR,
|
||||
"on_body_chunk keyword not inside of route context");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
current_route->on_body_chunk = kore_runtime_getcall(name);
|
||||
if (current_route->on_body_chunk == NULL) {
|
||||
kore_log(LOG_ERR,
|
||||
"on_body_chunk callback '%s' for '%s' not found",
|
||||
name, current_route->path);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_route_methods(char *options)
|
||||
{
|
||||
|
127
src/http.c
127
src/http.c
@ -130,6 +130,7 @@ static const char *pretty_error_fmt =
|
||||
static int http_body_recv(struct netbuf *);
|
||||
static int http_release_buffer(struct netbuf *);
|
||||
static void http_error_response(struct connection *, int);
|
||||
static int http_data_convert(void *, void **, void *, int);
|
||||
static void http_write_response_cookie(struct http_cookie *);
|
||||
static void http_argument_add(struct http_request *, char *, char *,
|
||||
int, int);
|
||||
@ -763,6 +764,28 @@ http_request_header(struct http_request *req, const char *header,
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
int
|
||||
http_request_header_get(struct http_request *req, const char *header,
|
||||
void **out, void *nout, int type)
|
||||
{
|
||||
struct http_header *hdr;
|
||||
|
||||
if (type == HTTP_ARG_TYPE_STRING)
|
||||
fatal("%s: cannot be called with type string", __func__);
|
||||
|
||||
TAILQ_FOREACH(hdr, &req->req_headers, list) {
|
||||
if (strcasecmp(hdr->header, header))
|
||||
continue;
|
||||
|
||||
if (http_data_convert(hdr->value, out, nout, type))
|
||||
return (KORE_RESULT_OK);
|
||||
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
int
|
||||
http_request_cookie(struct http_request *req, const char *cookie, char **out)
|
||||
{
|
||||
@ -786,7 +809,6 @@ http_header_recv(struct netbuf *nb)
|
||||
ssize_t ret;
|
||||
struct http_header *hdr;
|
||||
struct http_request *req;
|
||||
const char *clp;
|
||||
u_int64_t bytes_left;
|
||||
u_int8_t *end_headers;
|
||||
int h, i, v, skip, l;
|
||||
@ -897,17 +919,8 @@ http_header_recv(struct netbuf *nb)
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
if (!http_request_header(req, "content-length", &clp)) {
|
||||
kore_debug("expected body but no content-length");
|
||||
req->flags |= HTTP_REQUEST_DELETE;
|
||||
http_error_response(req->owner,
|
||||
HTTP_STATUS_LENGTH_REQUIRED);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
req->content_length = kore_strtonum(clp, 10, 0, LONG_MAX, &v);
|
||||
if (v == KORE_RESULT_ERROR) {
|
||||
kore_debug("content-length invalid: %s", clp);
|
||||
if (!http_request_header_uint64(req, "content-length",
|
||||
&req->content_length)) {
|
||||
req->flags |= HTTP_REQUEST_DELETE;
|
||||
http_error_response(req->owner,
|
||||
HTTP_STATUS_LENGTH_REQUIRED);
|
||||
@ -921,8 +934,6 @@ http_header_recv(struct netbuf *nb)
|
||||
}
|
||||
|
||||
if (req->content_length > http_body_max) {
|
||||
kore_log(LOG_NOTICE, "body too large (%zu > %zu)",
|
||||
req->content_length, http_body_max);
|
||||
req->flags |= HTTP_REQUEST_DELETE;
|
||||
http_error_response(req->owner,
|
||||
HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE);
|
||||
@ -997,6 +1008,13 @@ http_header_recv(struct netbuf *nb)
|
||||
c->http_timeout = 0;
|
||||
}
|
||||
|
||||
if (req->rt->on_headers != NULL) {
|
||||
if (!kore_runtime_http_request(req->rt->on_headers, req)) {
|
||||
req->flags |= HTTP_REQUEST_DELETE;
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
@ -1010,45 +1028,10 @@ http_argument_get(struct http_request *req, const char *name,
|
||||
if (strcmp(q->name, name))
|
||||
continue;
|
||||
|
||||
switch (type) {
|
||||
case HTTP_ARG_TYPE_RAW:
|
||||
*out = q->s_value;
|
||||
if (http_data_convert(q->s_value, out, nout, type))
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_BYTE:
|
||||
COPY_ARG_TYPE(*(u_int8_t *)q->s_value, u_int8_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT16:
|
||||
COPY_AS_INTTYPE(SHRT_MIN, SHRT_MAX, int16_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT16:
|
||||
COPY_AS_INTTYPE(0, USHRT_MAX, u_int16_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT32:
|
||||
COPY_AS_INTTYPE(INT_MIN, INT_MAX, int32_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT32:
|
||||
COPY_AS_INTTYPE(0, UINT_MAX, u_int32_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT64:
|
||||
COPY_AS_INTTYPE_64(int64_t, 1);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT64:
|
||||
COPY_AS_INTTYPE_64(u_int64_t, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_FLOAT:
|
||||
COPY_ARG_DOUBLE(-FLT_MAX, FLT_MAX, float);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_DOUBLE:
|
||||
COPY_ARG_DOUBLE(-DBL_MAX, DBL_MAX, double);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_STRING:
|
||||
*out = q->s_value;
|
||||
return (KORE_RESULT_OK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (KORE_RESULT_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
return (KORE_RESULT_ERROR);
|
||||
@ -2598,3 +2581,45 @@ http_write_response_cookie(struct http_cookie *ck)
|
||||
kore_buf_appendf(header_buf, "set-cookie: %s\r\n",
|
||||
kore_buf_stringify(ckhdr_buf, NULL));
|
||||
}
|
||||
|
||||
static int
|
||||
http_data_convert(void *data, void **out, void *nout, int type)
|
||||
{
|
||||
switch (type) {
|
||||
case HTTP_ARG_TYPE_RAW:
|
||||
case HTTP_ARG_TYPE_STRING:
|
||||
*out = data;
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_BYTE:
|
||||
COPY_ARG_TYPE(*(u_int8_t *)data, u_int8_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT16:
|
||||
COPY_AS_INTTYPE(SHRT_MIN, SHRT_MAX, int16_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT16:
|
||||
COPY_AS_INTTYPE(0, USHRT_MAX, u_int16_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT32:
|
||||
COPY_AS_INTTYPE(INT_MIN, INT_MAX, int32_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT32:
|
||||
COPY_AS_INTTYPE(0, UINT_MAX, u_int32_t);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_INT64:
|
||||
COPY_AS_INTTYPE_64(int64_t, 1);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_UINT64:
|
||||
COPY_AS_INTTYPE_64(u_int64_t, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_FLOAT:
|
||||
COPY_ARG_DOUBLE(-FLT_MAX, FLT_MAX, float);
|
||||
return (KORE_RESULT_OK);
|
||||
case HTTP_ARG_TYPE_DOUBLE:
|
||||
COPY_ARG_DOUBLE(-DBL_MAX, DBL_MAX, double);
|
||||
return (KORE_RESULT_OK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user