summaryrefslogtreecommitdiffhomepage
path: root/src/nxt_http_request.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nxt_http_request.c')
-rw-r--r--src/nxt_http_request.c317
1 files changed, 266 insertions, 51 deletions
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index 04a6f7f3..943ad82d 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -10,10 +10,14 @@
static nxt_int_t nxt_http_validate_host(nxt_str_t *host, nxt_mp_t *mp);
static void nxt_http_request_start(nxt_task_t *task, void *obj, void *data);
-static nxt_int_t nxt_http_request_client_ip(nxt_task_t *task,
- nxt_http_request_t *r);
+static nxt_int_t nxt_http_request_forward(nxt_task_t *task,
+ nxt_http_request_t *r, nxt_http_forward_t *forward);
+static void nxt_http_request_forward_client_ip(nxt_http_request_t *r,
+ nxt_http_forward_t *forward, nxt_array_t *fields);
static nxt_sockaddr_t *nxt_http_request_client_ip_sockaddr(
nxt_http_request_t *r, u_char *start, size_t len);
+static void nxt_http_request_forward_protocol(nxt_http_request_t *r,
+ nxt_http_field_t *field);
static void nxt_http_request_ready(nxt_task_t *task, void *obj, void *data);
static void nxt_http_request_proto_info(nxt_task_t *task,
nxt_http_request_t *r);
@@ -26,11 +30,11 @@ static u_char *nxt_http_date_cache_handler(u_char *buf, nxt_realtime_t *now,
static nxt_http_name_value_t *nxt_http_argument(nxt_array_t *array,
u_char *name, size_t name_length, uint32_t hash, u_char *start,
- u_char *end);
+ const u_char *end);
static nxt_int_t nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start,
- u_char *end);
+ const u_char *end);
static nxt_http_name_value_t *nxt_http_cookie(nxt_array_t *array, u_char *name,
- size_t name_length, u_char *start, u_char *end);
+ size_t name_length, u_char *start, const u_char *end);
#define NXT_HTTP_COOKIE_HASH \
@@ -274,6 +278,8 @@ nxt_http_request_create(nxt_task_t *task)
r->resp.content_length_n = -1;
r->state = &nxt_http_request_init_state;
+ task->thread->engine->requests_cnt++;
+
return r;
fail:
@@ -296,74 +302,125 @@ static void
nxt_http_request_start(nxt_task_t *task, void *obj, void *data)
{
nxt_int_t ret;
+ nxt_socket_conf_t *skcf;
nxt_http_request_t *r;
r = obj;
r->state = &nxt_http_request_body_state;
- ret = nxt_http_request_client_ip(task, r);
- if (nxt_slow_path(ret != NXT_OK)) {
- nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
+ skcf = r->conf->socket_conf;
+
+ if (skcf->forwarded != NULL) {
+ ret = nxt_http_request_forward(task, r, skcf->forwarded);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto fail;
+ }
+ }
+
+ if (skcf->client_ip != NULL) {
+ ret = nxt_http_request_forward(task, r, skcf->client_ip);
+ if (nxt_slow_path(ret != NXT_OK)) {
+ goto fail;
+ }
}
nxt_http_request_read_body(task, r);
+
+ return;
+
+fail:
+ nxt_http_request_error(task, r, NXT_HTTP_INTERNAL_SERVER_ERROR);
}
static nxt_int_t
-nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r)
+nxt_http_request_forward(nxt_task_t *task, nxt_http_request_t *r,
+ nxt_http_forward_t *forward)
{
- u_char *start, *p;
- nxt_int_t ret, i, len;
- nxt_str_t *header;
- nxt_array_t *fields_arr; /* of nxt_http_field_t * */
- nxt_sockaddr_t *sa, *prev_sa;
- nxt_http_field_t *f, **fields;
- nxt_http_client_ip_t *client_ip;
+ nxt_int_t ret;
+ nxt_array_t *client_ip_fields;
+ nxt_http_field_t *f, **fields, *protocol_field;
+ nxt_http_forward_header_t *client_ip, *protocol;
- client_ip = r->conf->socket_conf->client_ip;
-
- if (client_ip == NULL) {
- return NXT_OK;
- }
-
- ret = nxt_http_route_addr_rule(r, client_ip->source, r->remote);
+ ret = nxt_http_route_addr_rule(r, forward->source, r->remote);
if (ret <= 0) {
return NXT_OK;
}
- header = client_ip->header;
+ client_ip = &forward->client_ip;
+ protocol = &forward->protocol;
+
+ if (client_ip->header != NULL) {
+ client_ip_fields = nxt_array_create(r->mem_pool, 1,
+ sizeof(nxt_http_field_t *));
+ if (nxt_slow_path(client_ip_fields == NULL)) {
+ return NXT_ERROR;
+ }
- fields_arr = nxt_array_create(r->mem_pool, 2, sizeof(nxt_http_field_t *));
- if (nxt_slow_path(fields_arr == NULL)) {
- return NXT_ERROR;
+ } else {
+ client_ip_fields = NULL;
}
+ protocol_field = NULL;
+
nxt_list_each(f, r->fields) {
- if (f->hash == client_ip->header_hash
- && f->name_length == client_ip->header->length
+ if (client_ip_fields != NULL
+ && f->hash == client_ip->header_hash
&& f->value_length > 0
- && nxt_memcasecmp(f->name, header->start, header->length) == 0)
+ && f->name_length == client_ip->header->length
+ && nxt_memcasecmp(f->name, client_ip->header->start,
+ client_ip->header->length) == 0)
{
- fields = nxt_array_add(fields_arr);
+ fields = nxt_array_add(client_ip_fields);
if (nxt_slow_path(fields == NULL)) {
return NXT_ERROR;
}
*fields = f;
}
+
+ if (protocol->header != NULL
+ && protocol_field == NULL
+ && f->hash == protocol->header_hash
+ && f->value_length > 0
+ && f->name_length == protocol->header->length
+ && nxt_memcasecmp(f->name, protocol->header->start,
+ protocol->header->length) == 0)
+ {
+ protocol_field = f;
+ }
} nxt_list_loop;
+ if (client_ip_fields != NULL) {
+ nxt_http_request_forward_client_ip(r, forward, client_ip_fields);
+ }
+
+ if (protocol_field != NULL) {
+ nxt_http_request_forward_protocol(r, protocol_field);
+ }
+
+ return NXT_OK;
+}
+
+
+static void
+nxt_http_request_forward_client_ip(nxt_http_request_t *r,
+ nxt_http_forward_t *forward, nxt_array_t *fields)
+{
+ u_char *start, *p;
+ nxt_int_t ret, i, len;
+ nxt_sockaddr_t *sa, *prev_sa;
+ nxt_http_field_t **f;
+
prev_sa = r->remote;
- fields = (nxt_http_field_t **) fields_arr->elts;
+ f = (nxt_http_field_t **) fields->elts;
- i = fields_arr->nelts;
+ i = fields->nelts;
while (i-- > 0) {
- f = fields[i];
- start = f->value;
- len = f->value_length;
+ start = f[i]->value;
+ len = f[i]->value_length;
do {
for (p = start + len - 1; p > start; p--, len--) {
@@ -385,20 +442,18 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r)
r->remote = prev_sa;
}
- return NXT_OK;
+ return;
}
- if (!client_ip->recursive) {
+ if (!forward->recursive) {
r->remote = sa;
-
- return NXT_OK;
+ return;
}
- ret = nxt_http_route_addr_rule(r, client_ip->source, sa);
+ ret = nxt_http_route_addr_rule(r, forward->source, sa);
if (ret <= 0 || (i == 0 && p == start)) {
r->remote = sa;
-
- return NXT_OK;
+ return;
}
prev_sa = sa;
@@ -406,8 +461,6 @@ nxt_http_request_client_ip(nxt_task_t *task, nxt_http_request_t *r)
} while (len > 0);
}
-
- return NXT_OK;
}
@@ -451,6 +504,28 @@ nxt_http_request_client_ip_sockaddr(nxt_http_request_t *r, u_char *start,
}
+static void
+nxt_http_request_forward_protocol(nxt_http_request_t *r,
+ nxt_http_field_t *field)
+{
+ if (field->value_length == 4) {
+ if (nxt_memcasecmp(field->value, "http", 4) == 0) {
+ r->tls = 0;
+ }
+
+ } else if (field->value_length == 5) {
+ if (nxt_memcasecmp(field->value, "https", 5) == 0) {
+ r->tls = 1;
+ }
+
+ } else if (field->value_length == 2) {
+ if (nxt_memcasecmp(field->value, "on", 2) == 0) {
+ r->tls = 1;
+ }
+ }
+}
+
+
static const nxt_http_request_state_t nxt_http_request_body_state
nxt_aligned(64) =
{
@@ -718,6 +793,7 @@ nxt_http_request_error_handler(nxt_task_t *task, void *obj, void *data)
void
nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
{
+ nxt_var_t *log_format;
nxt_http_proto_t proto;
nxt_http_request_t *r;
nxt_http_protocol_t protocol;
@@ -727,20 +803,22 @@ nxt_http_request_close_handler(nxt_task_t *task, void *obj, void *data)
r = obj;
proto.any = data;
- nxt_debug(task, "http request close handler");
-
conf = r->conf;
if (!r->logged) {
r->logged = 1;
access_log = conf->socket_conf->router_conf->access_log;
+ log_format = conf->socket_conf->router_conf->log_format;
if (access_log != NULL) {
- access_log->handler(task, r, access_log);
+ access_log->handler(task, r, access_log, log_format);
+ return;
}
}
+ nxt_debug(task, "http request close handler");
+
r->proto.any = NULL;
if (r->body != NULL && nxt_buf_is_file(r->body)
@@ -876,7 +954,7 @@ nxt_http_arguments_parse(nxt_http_request_t *r)
static nxt_http_name_value_t *
nxt_http_argument(nxt_array_t *array, u_char *name, size_t name_length,
- uint32_t hash, u_char *start, u_char *end)
+ uint32_t hash, u_char *start, const u_char *end)
{
size_t length;
nxt_http_name_value_t *nv;
@@ -945,7 +1023,7 @@ nxt_http_cookies_parse(nxt_http_request_t *r)
static nxt_int_t
-nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
+nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, const u_char *end)
{
size_t name_length;
u_char c, *p, *name;
@@ -994,7 +1072,7 @@ nxt_http_cookie_parse(nxt_array_t *cookies, u_char *start, u_char *end)
static nxt_http_name_value_t *
nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length,
- u_char *start, u_char *end)
+ u_char *start, const u_char *end)
{
u_char c, *p;
uint32_t hash;
@@ -1024,3 +1102,140 @@ nxt_http_cookie(nxt_array_t *array, u_char *name, size_t name_length,
return nv;
}
+
+
+int64_t
+nxt_http_field_hash(nxt_mp_t *mp, nxt_str_t *name, nxt_bool_t case_sensitive,
+ uint8_t encoding)
+{
+ u_char c, *p, *src, *start, *end, plus;
+ uint8_t d0, d1;
+ uint32_t hash;
+ nxt_str_t str;
+ nxt_uint_t i;
+
+ str.length = name->length;
+
+ str.start = nxt_mp_nget(mp, str.length);
+ if (nxt_slow_path(str.start == NULL)) {
+ return -1;
+ }
+
+ p = str.start;
+
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+
+ if (encoding == NXT_HTTP_URI_ENCODING_NONE) {
+ for (i = 0; i < name->length; i++) {
+ c = name->start[i];
+ *p++ = c;
+
+ c = case_sensitive ? c : nxt_lowcase(c);
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+
+ goto end;
+ }
+
+ plus = (encoding == NXT_HTTP_URI_ENCODING_PLUS) ? ' ' : '+';
+
+ start = name->start;
+ end = start + name->length;
+
+ for (src = start; src < end; src++) {
+ c = *src;
+
+ switch (c) {
+ case '%':
+ if (nxt_slow_path(end - src <= 2)) {
+ return -1;
+ }
+
+ d0 = nxt_hex2int[src[1]];
+ d1 = nxt_hex2int[src[2]];
+ src += 2;
+
+ if (nxt_slow_path((d0 | d1) >= 16)) {
+ return -1;
+ }
+
+ c = (d0 << 4) + d1;
+ *p++ = c;
+ break;
+
+ case '+':
+ c = plus;
+ *p++ = c;
+ break;
+
+ default:
+ *p++ = c;
+ break;
+ }
+
+ c = case_sensitive ? c : nxt_lowcase(c);
+ hash = nxt_http_field_hash_char(hash, c);
+ }
+
+ str.length = p - str.start;
+
+end:
+
+ *name = str;
+
+ return nxt_http_field_hash_end(hash) & 0xFFFF;
+}
+
+
+int64_t
+nxt_http_argument_hash(nxt_mp_t *mp, nxt_str_t *name)
+{
+ return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_PLUS);
+}
+
+
+int64_t
+nxt_http_header_hash(nxt_mp_t *mp, nxt_str_t *name)
+{
+ u_char c, *p;
+ uint32_t i, hash;
+ nxt_str_t str;
+
+ str.length = name->length;
+
+ str.start = nxt_mp_nget(mp, str.length);
+ if (nxt_slow_path(str.start == NULL)) {
+ return -1;
+ }
+
+ p = str.start;
+ hash = NXT_HTTP_FIELD_HASH_INIT;
+
+ for (i = 0; i < name->length; i++) {
+ c = name->start[i];
+
+ if (c >= 'A' && c <= 'Z') {
+ *p = c | 0x20;
+
+ } else if (c == '_') {
+ *p = '-';
+
+ } else {
+ *p = c;
+ }
+
+ hash = nxt_http_field_hash_char(hash, *p);
+ p++;
+ }
+
+ *name = str;
+
+ return nxt_http_field_hash_end(hash) & 0xFFFF;
+}
+
+
+int64_t
+nxt_http_cookie_hash(nxt_mp_t *mp, nxt_str_t *name)
+{
+ return nxt_http_field_hash(mp, name, 1, NXT_HTTP_URI_ENCODING_NONE);
+}