summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMax Romanov <max.romanov@nginx.com>2017-07-05 13:31:45 +0300
committerMax Romanov <max.romanov@nginx.com>2017-07-05 13:31:45 +0300
commitf3107f3896c199a5bc166f57ccd9fef2823ccdaf (patch)
tree1bb2388940d3ad1be08ababfecd270c65289cf26
parentf05d674126f3ec3f147f645231a1357e4a0784bf (diff)
downloadunit-f3107f3896c199a5bc166f57ccd9fef2823ccdaf.tar.gz
unit-f3107f3896c199a5bc166f57ccd9fef2823ccdaf.tar.bz2
Complex target parser copied from NGINX.
nxt_app_request_header_t fields renamed: - 'path' renamed to 'target'. - 'path_no_query' renamed to 'path' and contains parsed value.
-rw-r--r--src/nginext/nxt_go_port.c17
-rw-r--r--src/nxt_application.c16
-rw-r--r--src/nxt_application.h4
-rw-r--r--src/nxt_controller.c9
-rw-r--r--src/nxt_go.c9
-rw-r--r--src/nxt_http_parse.c337
-rw-r--r--src/nxt_http_parse.h7
-rw-r--r--src/nxt_php_sapi.c38
-rw-r--r--src/nxt_python_wsgi.c30
9 files changed, 413 insertions, 54 deletions
diff --git a/src/nginext/nxt_go_port.c b/src/nginext/nxt_go_port.c
index 00d13a38..47e46f02 100644
--- a/src/nginext/nxt_go_port.c
+++ b/src/nginext/nxt_go_port.c
@@ -41,22 +41,27 @@ nxt_go_data_handler(nxt_port_msg_t *port_msg, size_t size)
h = &ctx->r.header;
nxt_go_ctx_read_str(ctx, &h->method);
+ nxt_go_ctx_read_str(ctx, &h->target);
nxt_go_ctx_read_str(ctx, &h->path);
- h->path_no_query = h->path;
nxt_go_ctx_read_size(ctx, &s);
if (s > 0) {
s--;
- h->query.start = h->path.start + s;
- h->query.length = h->path.length - s;
+ h->query.start = h->target.start + s;
+ h->query.length = h->target.length - s;
- if (s > 0) {
- h->path_no_query.length = s - 1;
+ if (h->path.start == NULL) {
+ h->path.start = h->target.start;
+ h->path.length = s - 1;
}
}
+ if (h->path.start == NULL) {
+ h->path = h->target;
+ }
+
nxt_go_new_request(r, port_msg->stream, nxt_go_str(&h->method),
- nxt_go_str(&h->path));
+ nxt_go_str(&h->target));
nxt_go_ctx_read_str(ctx, &h->version);
diff --git a/src/nxt_application.c b/src/nxt_application.c
index d7393de7..37e2577c 100644
--- a/src/nxt_application.c
+++ b/src/nxt_application.c
@@ -477,19 +477,11 @@ nxt_app_http_req_parse(nxt_task_t *task, nxt_app_parse_ctx_t *ctx,
h->method = p->method;
- h->path.start = p->target_start;
- h->path.length = p->target_end - p->target_start;
+ h->target.start = p->target_start;
+ h->target.length = p->target_end - p->target_start;
- h->path_no_query = h->path;
-
- if (p->args_start != NULL) {
- h->query.start = p->args_start;
- h->query.length = p->target_end - p->args_start;
-
- if (p->args_start > p->target_start) {
- h->path_no_query.length = p->args_start - p->target_start - 1;
- }
- }
+ h->path = p->path;
+ h->query = p->args;
if (h->parsed_content_length == 0) {
b->done = 1;
diff --git a/src/nxt_application.h b/src/nxt_application.h
index fe36ea4d..9d8b1054 100644
--- a/src/nxt_application.h
+++ b/src/nxt_application.h
@@ -17,10 +17,10 @@ typedef struct {
typedef struct {
nxt_str_t method;
+ nxt_str_t target;
+ nxt_str_t version;
nxt_str_t path;
- nxt_str_t path_no_query;
nxt_str_t query;
- nxt_str_t version;
nxt_list_t *fields;
diff --git a/src/nxt_controller.c b/src/nxt_controller.c
index 6898be6d..a3c0af17 100644
--- a/src/nxt_controller.c
+++ b/src/nxt_controller.c
@@ -554,14 +554,7 @@ nxt_controller_process_request(nxt_task_t *task, nxt_conn_t *c,
static const nxt_str_t empty_obj = nxt_string("{}");
- path.start = req->parser.target_start;
-
- if (req->parser.args_start != NULL) {
- path.length = req->parser.args_start - path.start;
-
- } else {
- path.length = req->parser.target_end - path.start;
- }
+ path = req->parser.path;
if (path.length > 1 && path.start[path.length - 1] == '/') {
path.length--;
diff --git a/src/nxt_go.c b/src/nxt_go.c
index 703974ba..4c77de0d 100644
--- a/src/nxt_go.c
+++ b/src/nxt_go.c
@@ -158,11 +158,16 @@ nxt_go_prepare_msg(nxt_task_t *task, nxt_app_request_t *r, nxt_app_wmsg_t *wmsg)
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
- NXT_WRITE(&h->path);
+ NXT_WRITE(&h->target);
+ if (h->path.start == h->target.start) {
+ NXT_WRITE(&eof);
+ } else {
+ NXT_WRITE(&h->path);
+ }
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
- h->query.start - h->path.start + 1));
+ h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
diff --git a/src/nxt_http_parse.c b/src/nxt_http_parse.c
index abdb23fa..946c8da2 100644
--- a/src/nxt_http_parse.c
+++ b/src/nxt_http_parse.c
@@ -49,6 +49,8 @@ static void nxt_http_fields_hash_lookup(nxt_http_fields_hash_t *hash,
static void nxt_http_fields_hash_lookup_long(nxt_http_fields_hash_t *hash,
nxt_http_field_t *field);
+static nxt_int_t nxt_http_parse_complex_target(nxt_http_request_parse_t *rp);
+
typedef enum {
NXT_HTTP_TARGET_SPACE = 1, /* \s */
@@ -349,10 +351,39 @@ space_after_target:
}
*pos = p + 1;
+
+ } else {
+ *pos = p + 10;
+ }
+
+ if (rp->complex_target != 0 || rp->quoted_target != 0) {
+ rc = nxt_http_parse_complex_target(rp);
+
+ if (nxt_slow_path(rc != NXT_OK)) {
+ return rc;
+ }
+
return nxt_http_parse_field_name(rp, pos, end);
}
- *pos = p + 10;
+ rp->path.start = rp->target_start;
+
+ if (rp->args_start != NULL) {
+ rp->path.length = rp->args_start - rp->target_start - 1;
+
+ rp->args.start = rp->args_start;
+ rp->args.length = rp->target_end - rp->args_start;
+
+ } else {
+ rp->path.length = rp->target_end - rp->target_start;
+ }
+
+ if (rp->exten_start) {
+ rp->exten.length = rp->path.start + rp->path.length -
+ rp->exten_start;
+ rp->exten.start = rp->exten_start;
+ }
+
return nxt_http_parse_field_name(rp, pos, end);
}
@@ -885,3 +916,307 @@ nxt_http_fields_process(nxt_list_t *fields, void *ctx, nxt_log_t *log)
return NXT_OK;
}
+
+
+#define \
+nxt_http_is_normal(c) \
+ (nxt_fast_path((nxt_http_normal[c / 8] & (1 << (c & 7))) != 0))
+
+
+static const uint8_t nxt_http_normal[32] nxt_aligned(32) = {
+
+ /* \0 \r \n */
+ 0xfe, 0xdb, 0xff, 0xff, /* 1111 1110 1101 1011 1111 1111 1111 1111 */
+
+ /* '&%$ #"! /.-, |*)( 7654 3210 ?>=< ;:98 */
+ 0xd6, 0x37, 0xff, 0x7f, /* 1101 0110 0011 0111 1111 1111 0111 1111 */
+
+ /* GFED CBA@ ONML KJIH WVUT SRQP _^]\ [ZYX */
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ /* gfed cba` onml kjih wvut srqp ~}| {zyx */
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+ 0xff, 0xff, 0xff, 0xff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
+};
+
+
+static nxt_int_t
+nxt_http_parse_complex_target(nxt_http_request_parse_t *rp)
+{
+ u_char *p, *u, c, ch, high;
+ enum {
+ sw_normal = 0,
+ sw_slash,
+ sw_dot,
+ sw_dot_dot,
+ sw_quoted,
+ sw_quoted_second,
+ } state, saved_state;
+
+ nxt_prefetch(nxt_http_normal);
+
+ state = sw_normal;
+ saved_state = sw_normal;
+ p = rp->target_start;
+
+ u = nxt_mp_alloc(rp->mem_pool, rp->target_end - p + 1);
+
+ if (nxt_slow_path(u == NULL)) {
+ return NXT_ERROR;
+ }
+
+ rp->path.length = 0;
+ rp->path.start = u;
+
+ high = '\0';
+ rp->exten_start = NULL;
+ rp->args_start = NULL;
+
+ while (p < rp->target_end) {
+
+ ch = *p++;
+
+ again:
+
+ switch (state) {
+
+ case sw_normal:
+
+ if (nxt_http_is_normal(ch)) {
+ *u++ = ch;
+ continue;
+ }
+
+ switch (ch) {
+ case '/':
+ rp->exten_start = NULL;
+ state = sw_slash;
+ *u++ = ch;
+ continue;
+ case '%':
+ saved_state = state;
+ state = sw_quoted;
+ continue;
+ case '?':
+ rp->args_start = p;
+ goto args;
+ case '#':
+ goto done;
+ case '.':
+ rp->exten_start = u + 1;
+ *u++ = ch;
+ continue;
+ case '+':
+ rp->plus_in_target = 1;
+ /* Fall through. */
+ default:
+ *u++ = ch;
+ continue;
+ }
+
+ break;
+
+ case sw_slash:
+
+ if (nxt_http_is_normal(ch)) {
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ switch (ch) {
+ case '/':
+ continue;
+ case '.':
+ state = sw_dot;
+ *u++ = ch;
+ continue;
+ case '%':
+ saved_state = state;
+ state = sw_quoted;
+ continue;
+ case '?':
+ rp->args_start = p;
+ goto args;
+ case '#':
+ goto done;
+ case '+':
+ rp->plus_in_target = 1;
+ /* Fall through. */
+ default:
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ break;
+
+ case sw_dot:
+
+ if (nxt_http_is_normal(ch)) {
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ switch (ch) {
+ case '/':
+ state = sw_slash;
+ u--;
+ continue;
+ case '.':
+ state = sw_dot_dot;
+ *u++ = ch;
+ continue;
+ case '%':
+ saved_state = state;
+ state = sw_quoted;
+ continue;
+ case '?':
+ rp->args_start = p;
+ goto args;
+ case '#':
+ goto done;
+ case '+':
+ rp->plus_in_target = 1;
+ /* Fall through. */
+ default:
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ break;
+
+ case sw_dot_dot:
+
+ if (nxt_http_is_normal(ch)) {
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ switch (ch) {
+ case '/':
+ state = sw_slash;
+ u -= 5;
+ for ( ;; ) {
+ if (u < rp->path.start) {
+ return NXT_ERROR;
+ }
+ if (*u == '/') {
+ u++;
+ break;
+ }
+ u--;
+ }
+ break;
+
+ case '%':
+ saved_state = state;
+ state = sw_quoted;
+ continue;
+ case '?':
+ rp->args_start = p;
+ goto args;
+ case '#':
+ goto done;
+ case '+':
+ rp->plus_in_target = 1;
+ /* Fall through. */
+ default:
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+ }
+
+ break;
+
+ case sw_quoted:
+ rp->quoted_target = 1;
+
+ if (ch >= '0' && ch <= '9') {
+ high = (u_char) (ch - '0');
+ state = sw_quoted_second;
+ continue;
+ }
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'f') {
+ high = (u_char) (c - 'a' + 10);
+ state = sw_quoted_second;
+ continue;
+ }
+
+ return NXT_ERROR;
+
+ case sw_quoted_second:
+ if (ch >= '0' && ch <= '9') {
+ ch = (u_char) ((high << 4) + ch - '0');
+
+ if (ch == '%' || ch == '#') {
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+
+ } else if (ch == '\0') {
+ return NXT_ERROR;
+ }
+
+ state = saved_state;
+ goto again;
+ }
+
+ c = (u_char) (ch | 0x20);
+ if (c >= 'a' && c <= 'f') {
+ ch = (u_char) ((high << 4) + c - 'a' + 10);
+
+ if (ch == '?') {
+ state = sw_normal;
+ *u++ = ch;
+ continue;
+
+ } else if (ch == '+') {
+ rp->plus_in_target = 1;
+ }
+
+ state = saved_state;
+ goto again;
+ }
+
+ return NXT_ERROR;
+ }
+ }
+
+ if (state >= sw_quoted) {
+ return NXT_ERROR;
+ }
+
+args:
+
+ for (/* void */; p < rp->target_end; p++) {
+ if (*p == '#') {
+ break;
+ }
+ }
+
+ if (rp->args_start != NULL) {
+ rp->args.length = p - rp->args_start;
+ rp->args.start = rp->args_start;
+ }
+
+done:
+
+ rp->path.length = u - rp->path.start;
+
+ if (rp->exten_start) {
+ rp->exten.length = u - rp->exten_start;
+ rp->exten.start = rp->exten_start;
+ }
+
+ return NXT_OK;
+}
diff --git a/src/nxt_http_parse.h b/src/nxt_http_parse.h
index da8c4ce6..2baa36ce 100644
--- a/src/nxt_http_parse.h
+++ b/src/nxt_http_parse.h
@@ -32,6 +32,10 @@ struct nxt_http_request_parse_s {
u_char *exten_start;
u_char *args_start;
+ nxt_str_t path;
+ nxt_str_t args;
+ nxt_str_t exten;
+
nxt_http_ver_t version;
union {
@@ -45,6 +49,7 @@ struct nxt_http_request_parse_s {
nxt_http_fields_hash_t *fields_hash;
nxt_list_t *fields;
+ nxt_mp_t *mem_pool;
/* target with "/." */
unsigned complex_target:1;
@@ -80,6 +85,8 @@ struct nxt_http_field_s {
nxt_inline nxt_int_t
nxt_http_parse_request_init(nxt_http_request_parse_t *rp, nxt_mp_t *mp)
{
+ rp->mem_pool = mp;
+
rp->fields = nxt_list_create(mp, 8, sizeof(nxt_http_field_t));
if (nxt_slow_path(rp->fields == NULL)){
return NXT_ERROR;
diff --git a/src/nxt_php_sapi.c b/src/nxt_php_sapi.c
index 28b6f406..b57d5c8f 100644
--- a/src/nxt_php_sapi.c
+++ b/src/nxt_php_sapi.c
@@ -244,28 +244,33 @@ nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg,
h = &ctx->r.header;
nxt_app_msg_read_str(task, rmsg, &h->method);
+ nxt_app_msg_read_str(task, rmsg, &h->target);
nxt_app_msg_read_str(task, rmsg, &h->path);
- h->path_no_query = h->path;
nxt_app_msg_read_size(task, rmsg, &s);
if (s > 0) {
s--;
- h->query.start = h->path.start + s;
- h->query.length = h->path.length - s;
+ h->query.start = h->target.start + s;
+ h->query.length = h->target.length - s;
- if (s > 0) {
- h->path_no_query.length = s - 1;
+ if (h->path.start == NULL) {
+ h->path.start = h->target.start;
+ h->path.length = s - 1;
}
}
+ if (h->path.start == NULL) {
+ h->path = h->target;
+ }
+
if (nxt_php_path.start == NULL) {
- if (h->path_no_query.start[h->path_no_query.length - 1] == '/') {
+ if (h->path.start[h->path.length - 1] == '/') {
script_name = nxt_php_index_name;
} else {
script_name.length = 0;
}
- ctx->script.length = nxt_php_root.length + h->path_no_query.length +
+ ctx->script.length = nxt_php_root.length + h->path.length +
script_name.length;
ctx->script.start = nxt_mp_nget(ctx->mem_pool,
ctx->script.length + 1);
@@ -275,8 +280,8 @@ nxt_php_read_request(nxt_task_t *task, nxt_app_rmsg_t *rmsg,
nxt_memcpy(p, nxt_php_root.start, nxt_php_root.length);
p += nxt_php_root.length;
- nxt_memcpy(p, h->path_no_query.start, h->path_no_query.length);
- p += h->path_no_query.length;
+ nxt_memcpy(p, h->path.start, h->path.length);
+ p += h->path.length;
if (script_name.length > 0) {
nxt_memcpy(p, script_name.start, script_name.length);
@@ -331,11 +336,16 @@ nxt_php_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
- NXT_WRITE(&h->path);
+ NXT_WRITE(&h->target);
+ if (h->path.start == h->target.start) {
+ NXT_WRITE(&eof);
+ } else {
+ NXT_WRITE(&h->path);
+ }
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
- h->query.start - h->path.start + 1));
+ h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
@@ -401,7 +411,7 @@ nxt_php_run(nxt_task_t *task,
nxt_php_read_request(task, rmsg, &run_ctx);
SG(server_context) = &run_ctx;
- SG(request_info).request_uri = (char *) h->path.start;
+ SG(request_info).request_uri = (char *) h->target.start;
SG(request_info).request_method = (char *) h->method.start;
SG(request_info).proto_num = 1001;
@@ -729,8 +739,8 @@ nxt_php_register_variables(zval *track_vars_array TSRMLS_DC)
h->method.length, track_vars_array TSRMLS_CC);
php_register_variable_safe((char *) "REQUEST_URI",
- (char *) h->path.start,
- h->path.length, track_vars_array TSRMLS_CC);
+ (char *) h->target.start,
+ h->target.length, track_vars_array TSRMLS_CC);
if (h->query.start != NULL) {
php_register_variable_safe((char *) "QUERY_STRING",
diff --git a/src/nxt_python_wsgi.c b/src/nxt_python_wsgi.c
index 70253b2c..9995e80b 100644
--- a/src/nxt_python_wsgi.c
+++ b/src/nxt_python_wsgi.c
@@ -420,11 +420,16 @@ nxt_python_prepare_msg(nxt_task_t *task, nxt_app_request_t *r,
/* TODO error handle, async mmap buffer assignment */
NXT_WRITE(&h->method);
- NXT_WRITE(&h->path);
+ NXT_WRITE(&h->target);
+ if (h->path.start == h->target.start) {
+ NXT_WRITE(&eof);
+ } else {
+ NXT_WRITE(&h->path);
+ }
if (h->query.start != NULL) {
RC(nxt_app_msg_write_size(task, wmsg,
- h->query.start - h->path.start + 1));
+ h->query.start - h->target.start + 1));
} else {
RC(nxt_app_msg_write_size(task, wmsg, 0));
}
@@ -763,7 +768,7 @@ nxt_python_get_environ(nxt_task_t *task, nxt_app_rmsg_t *rmsg)
size_t s;
PyObject *environ;
nxt_int_t rc;
- nxt_str_t n, v, path_no_query, query;
+ nxt_str_t n, v, target, path, query;
environ = PyDict_Copy(nxt_py_environ_ptyp);
@@ -787,22 +792,29 @@ nxt_python_get_environ(nxt_task_t *task, nxt_app_rmsg_t *rmsg)
NXT_READ("REQUEST_METHOD");
NXT_READ("REQUEST_URI");
- path_no_query = v; // assume no query
+ target = v;
+ RC(nxt_app_msg_read_str(task, rmsg, &path));
+
RC(nxt_app_msg_read_size(task, rmsg, &s)); // query length + 1
if (s > 0) {
s--;
- query.start = path_no_query.start + s;
- query.length = path_no_query.length - s;
+ query.start = target.start + s;
+ query.length = target.length - s;
RC(nxt_python_add_env(task, environ, "QUERY_STRING", &query));
- if (s > 0) {
- path_no_query.length = s - 1;
+ if (path.start == NULL) {
+ path.start = target.start;
+ path.length = s - 1;
}
}
- RC(nxt_python_add_env(task, environ, "PATH_INFO", &path_no_query));
+ if (path.start == NULL) {
+ path = target;
+ }
+
+ RC(nxt_python_add_env(task, environ, "PATH_INFO", &path));
NXT_READ("SERVER_PROTOCOL");