mirror of
https://github.com/jorisvink/kore
synced 2025-03-09 12:39:01 -04:00
Add support for config based redirection.
Inside the domain contexts a 'redirect' rule will allow you to redirect a request to another URI. Ex: Redirect all requests with a 301 to example.com redirect ^/.*$ 301 https://example.com Using capture groups redirect ^/account/(.*)$ 301 https://example.com/account/$1 Adding the query string in the mix redirect ^/(.*)$ 301 https://example.com/$1?$qs
This commit is contained in:
parent
6072828d8f
commit
fa2e8ef0b6
@ -10,8 +10,15 @@
|
||||
#socket_backlog 5000
|
||||
|
||||
# Server configuration.
|
||||
bind 127.0.0.1 443
|
||||
#bind_unix /var/run/kore.sock
|
||||
server tls {
|
||||
bind 127.0.0.1 443
|
||||
#bind_unix /var/run/kore.sock
|
||||
}
|
||||
|
||||
#server notls {
|
||||
# bind 127.0.0.1 80
|
||||
# tls no
|
||||
#}
|
||||
|
||||
# The worker process root directory. If chrooting was not disabled
|
||||
# at startup the worker processes will chroot into this directory.
|
||||
@ -276,6 +283,8 @@ authentication auth_example {
|
||||
|
||||
# Example domain that responds to localhost.
|
||||
domain localhost {
|
||||
attach tls
|
||||
|
||||
certfile cert/server.crt
|
||||
certkey cert/server.key
|
||||
accesslog /var/log/kore_access.log
|
||||
@ -334,6 +343,17 @@ domain localhost {
|
||||
}
|
||||
}
|
||||
|
||||
# Example redirect 80->443.
|
||||
#domain localhost {
|
||||
# attach notls
|
||||
#
|
||||
# # specific redirect with a capture group and arguments
|
||||
# redirect ^/account/(.*)$ 301 https://localhost/account/$1
|
||||
#
|
||||
# # redirect the others back to root.
|
||||
# redirect ^/.*$ 301 https://localhost
|
||||
#}
|
||||
|
||||
#domain domain.com {
|
||||
# certfile cert/other/server.crt
|
||||
# certkey cert/other/server.key
|
||||
|
@ -236,6 +236,13 @@ struct reqcall;
|
||||
struct kore_task;
|
||||
struct http_client;
|
||||
|
||||
struct http_redirect {
|
||||
regex_t rctx;
|
||||
int status;
|
||||
char *target;
|
||||
TAILQ_ENTRY(http_redirect) list;
|
||||
};
|
||||
|
||||
struct http_request {
|
||||
u_int8_t method;
|
||||
u_int8_t fsm_state;
|
||||
@ -345,6 +352,9 @@ int http_media_register(const char *, const char *);
|
||||
int http_check_timeout(struct connection *, u_int64_t);
|
||||
ssize_t http_body_read(struct http_request *, void *, size_t);
|
||||
int http_body_digest(struct http_request *, char *, size_t);
|
||||
|
||||
int http_redirect_add(struct kore_domain *,
|
||||
const char *, int, const char *);
|
||||
void http_response(struct http_request *, int, const void *, size_t);
|
||||
void http_response_fileref(struct http_request *, int,
|
||||
struct kore_fileref *);
|
||||
|
@ -134,6 +134,7 @@ extern int daemon(int, int);
|
||||
/* XXX hackish. */
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
struct http_request;
|
||||
struct http_redirect;
|
||||
#endif
|
||||
|
||||
#define KORE_FILEREF_SOFT_REMOVED 0x1000
|
||||
@ -323,6 +324,7 @@ struct kore_domain {
|
||||
int x509_verify_depth;
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
TAILQ_HEAD(, kore_module_handle) handlers;
|
||||
TAILQ_HEAD(, http_redirect) redirects;
|
||||
#endif
|
||||
TAILQ_ENTRY(kore_domain) list;
|
||||
};
|
||||
@ -927,7 +929,7 @@ int kore_module_handler_new(struct kore_domain *, const char *,
|
||||
const char *, const char *, int);
|
||||
void kore_module_handler_free(struct kore_module_handle *);
|
||||
struct kore_module_handle *kore_module_handler_find(struct http_request *,
|
||||
const char *, const char *);
|
||||
struct kore_domain *);
|
||||
#endif
|
||||
|
||||
struct kore_runtime_call *kore_runtime_getcall(const char *);
|
||||
|
33
src/config.c
33
src/config.c
@ -110,6 +110,7 @@ static int configure_client_verify_depth(char *);
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int configure_route(char *);
|
||||
static int configure_filemap(char *);
|
||||
static int configure_redirect(char *);
|
||||
static int configure_static_handler(char *);
|
||||
static int configure_dynamic_handler(char *);
|
||||
static int configure_restrict(char *);
|
||||
@ -189,6 +190,7 @@ static struct {
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
{ "route", configure_route},
|
||||
{ "filemap", configure_filemap },
|
||||
{ "redirect", configure_redirect },
|
||||
{ "static", configure_static_handler },
|
||||
{ "dynamic", configure_dynamic_handler },
|
||||
{ "accesslog", configure_accesslog },
|
||||
@ -1026,6 +1028,37 @@ configure_route(char *options)
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_redirect(char *options)
|
||||
{
|
||||
char *argv[4];
|
||||
int elm, status, err;
|
||||
|
||||
if (current_domain == NULL) {
|
||||
printf("redirect outside of domain context\n");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
elm = kore_split_string(options, " ", argv, 4);
|
||||
if (elm != 3) {
|
||||
printf("missing parameters for redirect\n");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
status = kore_strtonum(argv[1], 10, 300, 399, &err);
|
||||
if (err != KORE_RESULT_OK) {
|
||||
printf("invalid status code on redirect (%s)\n", argv[1]);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (!http_redirect_add(current_domain, argv[0], status, argv[2])) {
|
||||
printf("invalid regex on redirect path\n");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
configure_filemap(char *options)
|
||||
{
|
||||
|
11
src/domain.c
11
src/domain.c
@ -188,6 +188,7 @@ kore_domain_new(const char *domain)
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
TAILQ_INIT(&(dom->handlers));
|
||||
TAILQ_INIT(&(dom->redirects));
|
||||
#endif
|
||||
|
||||
if (dom->id < KORE_DOMAIN_CACHE) {
|
||||
@ -225,7 +226,8 @@ void
|
||||
kore_domain_free(struct kore_domain *dom)
|
||||
{
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
struct kore_module_handle *hdlr;
|
||||
struct http_redirect *rdr;
|
||||
struct kore_module_handle *hdlr;
|
||||
#endif
|
||||
if (dom == NULL)
|
||||
return;
|
||||
@ -255,6 +257,13 @@ kore_domain_free(struct kore_domain *dom)
|
||||
TAILQ_REMOVE(&(dom->handlers), hdlr, list);
|
||||
kore_module_handler_free(hdlr);
|
||||
}
|
||||
|
||||
while ((rdr = TAILQ_FIRST(&(dom->redirects))) != NULL) {
|
||||
TAILQ_REMOVE(&(dom->redirects), rdr, list);
|
||||
regfree(&rdr->rctx);
|
||||
kore_free(rdr->target);
|
||||
kore_free(rdr);
|
||||
}
|
||||
#endif
|
||||
kore_free(dom);
|
||||
}
|
||||
|
115
src/http.c
115
src/http.c
@ -123,6 +123,8 @@ static void http_error_response(struct connection *, int);
|
||||
static void http_write_response_cookie(struct http_cookie *);
|
||||
static void http_argument_add(struct http_request *, char *, char *,
|
||||
int, int);
|
||||
static int http_check_redirect(struct http_request *,
|
||||
struct kore_domain *);
|
||||
static void http_response_normal(struct http_request *,
|
||||
struct connection *, int, const void *, size_t);
|
||||
static void multipart_add_field(struct http_request *, struct kore_buf *,
|
||||
@ -1482,13 +1484,82 @@ http_runlock_release(struct http_runlock *lock, struct http_request *req)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
http_redirect_add(struct kore_domain *dom, const char *path, int status,
|
||||
const char *target)
|
||||
{
|
||||
struct http_redirect *rdr;
|
||||
|
||||
rdr = kore_calloc(1, sizeof(*rdr));
|
||||
|
||||
if (regcomp(&(rdr->rctx), path, REG_EXTENDED)) {
|
||||
kore_free(rdr);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
rdr->status = status;
|
||||
rdr->target = kore_strdup(target);
|
||||
|
||||
TAILQ_INSERT_TAIL(&dom->redirects, rdr, list);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static int
|
||||
http_check_redirect(struct http_request *req, struct kore_domain *dom)
|
||||
{
|
||||
int idx;
|
||||
struct http_redirect *rdr;
|
||||
const char *uri;
|
||||
char key[4];
|
||||
struct kore_buf location;
|
||||
|
||||
TAILQ_FOREACH(rdr, &dom->redirects, list) {
|
||||
if (!regexec(&(rdr->rctx), req->path,
|
||||
HTTP_CAPTURE_GROUPS, req->cgroups, 0))
|
||||
break;
|
||||
}
|
||||
|
||||
if (rdr == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
kore_buf_init(&location, 128);
|
||||
kore_buf_appendf(&location, "%s", rdr->target);
|
||||
|
||||
if (req->query_string != NULL) {
|
||||
kore_buf_replace_string(&location, "$qs",
|
||||
req->query_string, strlen(req->query_string));
|
||||
}
|
||||
|
||||
/* Starts at 1 to skip the full path. */
|
||||
for (idx = 1; idx < HTTP_CAPTURE_GROUPS - 1; idx++) {
|
||||
if (req->cgroups[idx].rm_so == -1 ||
|
||||
req->cgroups[idx].rm_eo == -1)
|
||||
break;
|
||||
|
||||
(void)snprintf(key, sizeof(key), "$%d", idx);
|
||||
|
||||
kore_buf_replace_string(&location, key,
|
||||
req->path + req->cgroups[idx].rm_so,
|
||||
req->cgroups[idx].rm_eo - req->cgroups[idx].rm_so);
|
||||
}
|
||||
|
||||
uri = kore_buf_stringify(&location, NULL);
|
||||
|
||||
http_response_header(req, "location", uri);
|
||||
http_response(req, rdr->status, NULL, 0);
|
||||
|
||||
kore_buf_cleanup(&location);
|
||||
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
static struct http_request *
|
||||
http_request_new(struct connection *c, const char *host,
|
||||
const char *method, char *path, const char *version)
|
||||
{
|
||||
struct kore_domain *dom;
|
||||
struct http_request *req;
|
||||
struct kore_module_handle *hdlr;
|
||||
char *p, *hp;
|
||||
int m, flags;
|
||||
size_t hostlen, pathlen, qsoff;
|
||||
@ -1523,7 +1594,6 @@ http_request_new(struct connection *c, const char *host,
|
||||
}
|
||||
|
||||
if ((p = strchr(path, '?')) != NULL) {
|
||||
*p = '\0';
|
||||
qsoff = p - path;
|
||||
} else {
|
||||
qsoff = 0;
|
||||
@ -1568,21 +1638,9 @@ http_request_new(struct connection *c, const char *host,
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
req = kore_pool_get(&http_request_pool);
|
||||
req->owner = c;
|
||||
|
||||
if ((hdlr = kore_module_handler_find(req, host, path)) == NULL) {
|
||||
kore_pool_put(&http_request_pool, req);
|
||||
http_error_response(c, 404);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (hp != NULL)
|
||||
*hp = ':';
|
||||
|
||||
if (p != NULL)
|
||||
*p = '?';
|
||||
|
||||
if (!strcasecmp(method, "get")) {
|
||||
m = HTTP_METHOD_GET;
|
||||
flags |= HTTP_REQUEST_COMPLETE;
|
||||
@ -1605,7 +1663,6 @@ http_request_new(struct connection *c, const char *host,
|
||||
m = HTTP_METHOD_PATCH;
|
||||
flags |= HTTP_REQUEST_EXPECT_BODY;
|
||||
} else {
|
||||
kore_pool_put(&http_request_pool, req);
|
||||
http_error_response(c, 400);
|
||||
return (NULL);
|
||||
}
|
||||
@ -1613,17 +1670,12 @@ http_request_new(struct connection *c, const char *host,
|
||||
if (flags & HTTP_VERSION_1_0) {
|
||||
if (m != HTTP_METHOD_GET && m != HTTP_METHOD_POST &&
|
||||
m != HTTP_METHOD_HEAD) {
|
||||
kore_pool_put(&http_request_pool, req);
|
||||
http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED);
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(hdlr->methods & m)) {
|
||||
kore_pool_put(&http_request_pool, req);
|
||||
http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED);
|
||||
return (NULL);
|
||||
}
|
||||
req = kore_pool_get(&http_request_pool);
|
||||
|
||||
req->end = 0;
|
||||
req->total = 0;
|
||||
@ -1631,7 +1683,6 @@ http_request_new(struct connection *c, const char *host,
|
||||
req->owner = c;
|
||||
req->status = 0;
|
||||
req->method = m;
|
||||
req->hdlr = hdlr;
|
||||
req->agent = NULL;
|
||||
req->onfree = NULL;
|
||||
req->referer = NULL;
|
||||
@ -1663,6 +1714,9 @@ http_request_new(struct connection *c, const char *host,
|
||||
req->query_string = NULL;
|
||||
}
|
||||
|
||||
/* Checked further down below if we need to 404. */
|
||||
req->hdlr = kore_module_handler_find(req, dom);
|
||||
|
||||
TAILQ_INIT(&(req->resp_headers));
|
||||
TAILQ_INIT(&(req->req_headers));
|
||||
TAILQ_INIT(&(req->resp_cookies));
|
||||
@ -1682,6 +1736,23 @@ http_request_new(struct connection *c, const char *host,
|
||||
TAILQ_INSERT_HEAD(&http_requests, req, list);
|
||||
TAILQ_INSERT_TAIL(&(c->http_requests), req, olist);
|
||||
|
||||
if (http_check_redirect(req, dom)) {
|
||||
http_request_free(req);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (req->hdlr == NULL) {
|
||||
http_request_free(req);
|
||||
http_error_response(c, HTTP_STATUS_NOT_FOUND);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!(req->hdlr->methods & m)) {
|
||||
http_request_free(req);
|
||||
http_error_response(c, HTTP_STATUS_METHOD_NOT_ALLOWED);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (req);
|
||||
}
|
||||
|
||||
|
11
src/module.c
11
src/module.c
@ -284,24 +284,19 @@ kore_module_handler_free(struct kore_module_handle *hdlr)
|
||||
}
|
||||
|
||||
struct kore_module_handle *
|
||||
kore_module_handler_find(struct http_request *req, const char *domain,
|
||||
const char *path)
|
||||
kore_module_handler_find(struct http_request *req, struct kore_domain *dom)
|
||||
{
|
||||
struct connection *c;
|
||||
struct kore_domain *dom;
|
||||
struct kore_module_handle *hdlr;
|
||||
|
||||
c = req->owner;
|
||||
|
||||
if ((dom = kore_domain_lookup(c->owner->server, domain)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
|
||||
if (hdlr->type == HANDLER_TYPE_STATIC) {
|
||||
if (!strcmp(hdlr->path, path))
|
||||
if (!strcmp(hdlr->path, req->path))
|
||||
return (hdlr);
|
||||
} else {
|
||||
if (!regexec(&(hdlr->rctx), path,
|
||||
if (!regexec(&(hdlr->rctx), req->path,
|
||||
HTTP_CAPTURE_GROUPS, req->cgroups, 0))
|
||||
return (hdlr);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user