Added routing based on request scheme.
Scheme matches exact string “http” or “https”.
This commit is contained in:
@@ -72,6 +72,8 @@ static nxt_int_t nxt_conf_vldt_match_patterns_set(nxt_conf_validation_t *vldt,
|
|||||||
nxt_conf_value_t *value);
|
nxt_conf_value_t *value);
|
||||||
static nxt_int_t nxt_conf_vldt_match_patterns_set_member(
|
static nxt_int_t nxt_conf_vldt_match_patterns_set_member(
|
||||||
nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
|
nxt_conf_validation_t *vldt, nxt_str_t *name, nxt_conf_value_t *value);
|
||||||
|
static nxt_int_t nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
|
||||||
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_app_name(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data);
|
nxt_conf_value_t *value, void *data);
|
||||||
static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
|
static nxt_int_t nxt_conf_vldt_app(nxt_conf_validation_t *vldt,
|
||||||
@@ -214,6 +216,11 @@ static nxt_conf_vldt_object_t nxt_conf_vldt_match_members[] = {
|
|||||||
&nxt_conf_vldt_match_patterns,
|
&nxt_conf_vldt_match_patterns,
|
||||||
NULL },
|
NULL },
|
||||||
|
|
||||||
|
{ nxt_string("scheme"),
|
||||||
|
NXT_CONF_VLDT_STRING,
|
||||||
|
&nxt_conf_vldt_match_scheme_pattern,
|
||||||
|
NULL },
|
||||||
|
|
||||||
{ nxt_string("host"),
|
{ nxt_string("host"),
|
||||||
NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
|
NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
|
||||||
&nxt_conf_vldt_match_patterns,
|
&nxt_conf_vldt_match_patterns,
|
||||||
@@ -819,6 +826,28 @@ nxt_conf_vldt_match_pattern(nxt_conf_validation_t *vldt,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_conf_vldt_match_scheme_pattern(nxt_conf_validation_t *vldt,
|
||||||
|
nxt_conf_value_t *value, void *data)
|
||||||
|
{
|
||||||
|
nxt_str_t scheme;
|
||||||
|
|
||||||
|
static const nxt_str_t http = nxt_string("http");
|
||||||
|
static const nxt_str_t https = nxt_string("https");
|
||||||
|
|
||||||
|
nxt_conf_get_string(value, &scheme);
|
||||||
|
|
||||||
|
if (nxt_strcasestr_eq(&scheme, &http)
|
||||||
|
|| nxt_strcasestr_eq(&scheme, &https))
|
||||||
|
{
|
||||||
|
return NXT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nxt_conf_vldt_error(vldt, "The \"scheme\" can either be "
|
||||||
|
"\"http\" or \"https\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t
|
static nxt_int_t
|
||||||
nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
|
nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
|
||||||
nxt_conf_value_t *value, void *data)
|
nxt_conf_value_t *value, void *data)
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ static void nxt_h1p_request_body_read(nxt_task_t *task, nxt_http_request_t *r);
|
|||||||
static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
|
static void nxt_h1p_conn_request_body_read(nxt_task_t *task, void *obj,
|
||||||
void *data);
|
void *data);
|
||||||
static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
|
static void nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r);
|
||||||
static void nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r);
|
|
||||||
static void nxt_h1p_request_header_send(nxt_task_t *task,
|
static void nxt_h1p_request_header_send(nxt_task_t *task,
|
||||||
nxt_http_request_t *r);
|
nxt_http_request_t *r);
|
||||||
static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
|
static void nxt_h1p_request_send(nxt_task_t *task, nxt_http_request_t *r,
|
||||||
@@ -104,13 +103,6 @@ const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[3] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const nxt_http_proto_tls_t nxt_http_proto_tls[3] = {
|
|
||||||
nxt_h1p_request_tls,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = {
|
const nxt_http_proto_header_send_t nxt_http_proto_header_send[3] = {
|
||||||
nxt_h1p_request_header_send,
|
nxt_h1p_request_header_send,
|
||||||
NULL,
|
NULL,
|
||||||
@@ -448,6 +440,10 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
|
|||||||
|
|
||||||
r->remote = c->remote;
|
r->remote = c->remote;
|
||||||
|
|
||||||
|
#if (NXT_TLS)
|
||||||
|
r->tls = c->u.tls;
|
||||||
|
#endif
|
||||||
|
|
||||||
ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
|
ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
|
||||||
|
|
||||||
if (nxt_fast_path(ret == NXT_OK)) {
|
if (nxt_fast_path(ret == NXT_OK)) {
|
||||||
@@ -821,15 +817,6 @@ nxt_h1p_request_local_addr(nxt_task_t *task, nxt_http_request_t *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
nxt_h1p_request_tls(nxt_task_t *task, nxt_http_request_t *r)
|
|
||||||
{
|
|
||||||
#if (NXT_TLS)
|
|
||||||
r->tls = r->proto.h1->conn->u.tls;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define NXT_HTTP_LAST_SUCCESS \
|
#define NXT_HTTP_LAST_SUCCESS \
|
||||||
(NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
|
(NXT_HTTP_OK + nxt_nitems(nxt_http_success) - 1)
|
||||||
|
|
||||||
|
|||||||
@@ -172,7 +172,6 @@ typedef void (*nxt_http_proto_body_read_t)(nxt_task_t *task,
|
|||||||
nxt_http_request_t *r);
|
nxt_http_request_t *r);
|
||||||
typedef void (*nxt_http_proto_local_addr_t)(nxt_task_t *task,
|
typedef void (*nxt_http_proto_local_addr_t)(nxt_task_t *task,
|
||||||
nxt_http_request_t *r);
|
nxt_http_request_t *r);
|
||||||
typedef void (*nxt_http_proto_tls_t)(nxt_task_t *task, nxt_http_request_t *r);
|
|
||||||
typedef void (*nxt_http_proto_header_send_t)(nxt_task_t *task,
|
typedef void (*nxt_http_proto_header_send_t)(nxt_task_t *task,
|
||||||
nxt_http_request_t *r);
|
nxt_http_request_t *r);
|
||||||
typedef void (*nxt_http_proto_send_t)(nxt_task_t *task, nxt_http_request_t *r,
|
typedef void (*nxt_http_proto_send_t)(nxt_task_t *task, nxt_http_request_t *r,
|
||||||
@@ -228,7 +227,6 @@ extern nxt_lvlhsh_t nxt_response_fields_hash;
|
|||||||
|
|
||||||
extern const nxt_http_proto_body_read_t nxt_http_proto_body_read[];
|
extern const nxt_http_proto_body_read_t nxt_http_proto_body_read[];
|
||||||
extern const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[];
|
extern const nxt_http_proto_local_addr_t nxt_http_proto_local_addr[];
|
||||||
extern const nxt_http_proto_tls_t nxt_http_proto_tls[];
|
|
||||||
extern const nxt_http_proto_header_send_t nxt_http_proto_header_send[];
|
extern const nxt_http_proto_header_send_t nxt_http_proto_header_send[];
|
||||||
extern const nxt_http_proto_send_t nxt_http_proto_send[];
|
extern const nxt_http_proto_send_t nxt_http_proto_send[];
|
||||||
extern const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[];
|
extern const nxt_http_proto_body_bytes_sent_t nxt_http_proto_body_bytes_sent[];
|
||||||
|
|||||||
@@ -357,7 +357,6 @@ nxt_http_request_proto_info(nxt_task_t *task, nxt_http_request_t *r)
|
|||||||
{
|
{
|
||||||
if (r->proto.any != NULL) {
|
if (r->proto.any != NULL) {
|
||||||
nxt_http_proto_local_addr[r->protocol](task, r);
|
nxt_http_proto_local_addr[r->protocol](task, r);
|
||||||
nxt_http_proto_tls[r->protocol](task, r);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ typedef enum {
|
|||||||
NXT_HTTP_ROUTE_HEADER,
|
NXT_HTTP_ROUTE_HEADER,
|
||||||
NXT_HTTP_ROUTE_ARGUMENT,
|
NXT_HTTP_ROUTE_ARGUMENT,
|
||||||
NXT_HTTP_ROUTE_COOKIE,
|
NXT_HTTP_ROUTE_COOKIE,
|
||||||
|
NXT_HTTP_ROUTE_SCHEME,
|
||||||
} nxt_http_route_object_t;
|
} nxt_http_route_object_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -41,6 +42,7 @@ typedef struct {
|
|||||||
nxt_conf_value_t *headers;
|
nxt_conf_value_t *headers;
|
||||||
nxt_conf_value_t *arguments;
|
nxt_conf_value_t *arguments;
|
||||||
nxt_conf_value_t *cookies;
|
nxt_conf_value_t *cookies;
|
||||||
|
nxt_conf_value_t *scheme;
|
||||||
} nxt_http_route_match_conf_t;
|
} nxt_http_route_match_conf_t;
|
||||||
|
|
||||||
|
|
||||||
@@ -197,6 +199,8 @@ static nxt_http_name_value_t *nxt_http_route_argument(nxt_array_t *array,
|
|||||||
u_char *end);
|
u_char *end);
|
||||||
static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
|
static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
|
||||||
nxt_http_route_rule_t *rule, nxt_array_t *array);
|
nxt_http_route_rule_t *rule, nxt_array_t *array);
|
||||||
|
static nxt_int_t nxt_http_route_scheme(nxt_http_request_t *r,
|
||||||
|
nxt_http_route_rule_t *rule);
|
||||||
static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
|
static nxt_int_t nxt_http_route_cookies(nxt_http_request_t *r,
|
||||||
nxt_http_route_rule_t *rule);
|
nxt_http_route_rule_t *rule);
|
||||||
static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
|
static nxt_array_t *nxt_http_route_cookies_parse(nxt_http_request_t *r);
|
||||||
@@ -276,6 +280,11 @@ nxt_http_routes_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
|||||||
|
|
||||||
|
|
||||||
static nxt_conf_map_t nxt_http_route_match_conf[] = {
|
static nxt_conf_map_t nxt_http_route_match_conf[] = {
|
||||||
|
{
|
||||||
|
nxt_string("scheme"),
|
||||||
|
NXT_CONF_MAP_PTR,
|
||||||
|
offsetof(nxt_http_route_match_conf_t, scheme)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
nxt_string("host"),
|
nxt_string("host"),
|
||||||
NXT_CONF_MAP_PTR,
|
NXT_CONF_MAP_PTR,
|
||||||
@@ -412,6 +421,18 @@ nxt_http_route_match_create(nxt_task_t *task, nxt_router_temp_conf_t *tmcf,
|
|||||||
|
|
||||||
test = &match->test[0];
|
test = &match->test[0];
|
||||||
|
|
||||||
|
if (mtcf.scheme != NULL) {
|
||||||
|
rule = nxt_http_route_rule_create(task, mp, mtcf.scheme, 1,
|
||||||
|
NXT_HTTP_ROUTE_PATTERN_NOCASE);
|
||||||
|
if (rule == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rule->object = NXT_HTTP_ROUTE_SCHEME;
|
||||||
|
test->rule = rule;
|
||||||
|
test++;
|
||||||
|
}
|
||||||
|
|
||||||
if (mtcf.host != NULL) {
|
if (mtcf.host != NULL) {
|
||||||
rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
|
rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
|
||||||
NXT_HTTP_ROUTE_PATTERN_LOWCASE);
|
NXT_HTTP_ROUTE_PATTERN_LOWCASE);
|
||||||
@@ -1125,6 +1146,9 @@ nxt_http_route_rule(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
|
|||||||
case NXT_HTTP_ROUTE_COOKIE:
|
case NXT_HTTP_ROUTE_COOKIE:
|
||||||
return nxt_http_route_cookies(r, rule);
|
return nxt_http_route_cookies(r, rule);
|
||||||
|
|
||||||
|
case NXT_HTTP_ROUTE_SCHEME:
|
||||||
|
return nxt_http_route_scheme(r, rule);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1330,6 +1354,18 @@ nxt_http_route_test_argument(nxt_http_request_t *r,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static nxt_int_t
|
||||||
|
nxt_http_route_scheme(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
|
||||||
|
{
|
||||||
|
nxt_bool_t tls, https;
|
||||||
|
|
||||||
|
https = (rule->pattern[0].length1 == nxt_length("https"));
|
||||||
|
tls = (r->tls != NULL);
|
||||||
|
|
||||||
|
return (tls == https);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static nxt_int_t
|
static nxt_int_t
|
||||||
nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
|
nxt_http_route_cookies(nxt_http_request_t *r, nxt_http_route_rule_t *rule)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2641,5 +2641,99 @@ class TestRouting(TestApplicationProto):
|
|||||||
'match cookies array 10',
|
'match cookies array 10',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_routes_match_scheme(self):
|
||||||
|
self.assertIn(
|
||||||
|
'success',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "http"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'match scheme http configure',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'success',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "https"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'match scheme https configure',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'success',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "HtTp"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'match scheme http case insensitive configure',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'success',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "HtTpS"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'match scheme https case insensitive configure',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_routes_match_scheme_invalid(self):
|
||||||
|
self.assertIn(
|
||||||
|
'error',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": ["http"]},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme invalid type no arrays allowed',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'error',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "ftp"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme invalid protocol 1',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'error',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "ws"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme invalid protocol 2',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'error',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": "*"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme invalid no wildcard allowed',
|
||||||
|
)
|
||||||
|
self.assertIn(
|
||||||
|
'error',
|
||||||
|
self.route(
|
||||||
|
{
|
||||||
|
"match": {"scheme": ""},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme invalid empty',
|
||||||
|
)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
TestRouting.main()
|
TestRouting.main()
|
||||||
|
|||||||
58
test/test_routing_tls.py
Normal file
58
test/test_routing_tls.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
from unit.applications.tls import TestApplicationTLS
|
||||||
|
|
||||||
|
|
||||||
|
class TestRoutingTLS(TestApplicationTLS):
|
||||||
|
prerequisites = ['python', 'openssl']
|
||||||
|
|
||||||
|
def test_routes_match_scheme(self):
|
||||||
|
self.certificate()
|
||||||
|
|
||||||
|
self.assertIn(
|
||||||
|
'success',
|
||||||
|
self.conf(
|
||||||
|
{
|
||||||
|
"listeners": {
|
||||||
|
"*:7080": {"pass": "routes"},
|
||||||
|
"*:7081": {
|
||||||
|
"pass": "routes",
|
||||||
|
"tls": {"certificate": 'default'},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"routes": [
|
||||||
|
{
|
||||||
|
"match": {"scheme": "http"},
|
||||||
|
"action": {"pass": "applications/empty"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"match": {"scheme": "https"},
|
||||||
|
"action": {"pass": "applications/204_no_content"},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"applications": {
|
||||||
|
"empty": {
|
||||||
|
"type": "python",
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": self.current_dir + "/python/empty",
|
||||||
|
"module": "wsgi",
|
||||||
|
},
|
||||||
|
"204_no_content": {
|
||||||
|
"type": "python",
|
||||||
|
"processes": {"spare": 0},
|
||||||
|
"path": self.current_dir
|
||||||
|
+ "/python/204_no_content",
|
||||||
|
"module": "wsgi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
),
|
||||||
|
'scheme configure',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(self.get()['status'], 200, 'scheme http')
|
||||||
|
self.assertEqual(
|
||||||
|
self.get_ssl(port=7081)['status'], 204, 'scheme https'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
TestRoutingTLS.main()
|
||||||
Reference in New Issue
Block a user