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);
|
||||
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);
|
||||
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,
|
||||
nxt_conf_value_t *value, void *data);
|
||||
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,
|
||||
NULL },
|
||||
|
||||
{ nxt_string("scheme"),
|
||||
NXT_CONF_VLDT_STRING,
|
||||
&nxt_conf_vldt_match_scheme_pattern,
|
||||
NULL },
|
||||
|
||||
{ nxt_string("host"),
|
||||
NXT_CONF_VLDT_STRING | NXT_CONF_VLDT_ARRAY,
|
||||
&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
|
||||
nxt_conf_vldt_match_patterns_sets(nxt_conf_validation_t *vldt,
|
||||
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,
|
||||
void *data);
|
||||
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,
|
||||
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] = {
|
||||
nxt_h1p_request_header_send,
|
||||
NULL,
|
||||
@@ -448,6 +440,10 @@ nxt_h1p_conn_request_init(nxt_task_t *task, void *obj, void *data)
|
||||
|
||||
r->remote = c->remote;
|
||||
|
||||
#if (NXT_TLS)
|
||||
r->tls = c->u.tls;
|
||||
#endif
|
||||
|
||||
ret = nxt_http_parse_request_init(&h1p->parser, r->mem_pool);
|
||||
|
||||
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 \
|
||||
(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);
|
||||
typedef void (*nxt_http_proto_local_addr_t)(nxt_task_t *task,
|
||||
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,
|
||||
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_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_send_t nxt_http_proto_send[];
|
||||
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) {
|
||||
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_ARGUMENT,
|
||||
NXT_HTTP_ROUTE_COOKIE,
|
||||
NXT_HTTP_ROUTE_SCHEME,
|
||||
} nxt_http_route_object_t;
|
||||
|
||||
|
||||
@@ -41,6 +42,7 @@ typedef struct {
|
||||
nxt_conf_value_t *headers;
|
||||
nxt_conf_value_t *arguments;
|
||||
nxt_conf_value_t *cookies;
|
||||
nxt_conf_value_t *scheme;
|
||||
} 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);
|
||||
static nxt_int_t nxt_http_route_test_argument(nxt_http_request_t *r,
|
||||
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,
|
||||
nxt_http_route_rule_t *rule);
|
||||
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[] = {
|
||||
{
|
||||
nxt_string("scheme"),
|
||||
NXT_CONF_MAP_PTR,
|
||||
offsetof(nxt_http_route_match_conf_t, scheme)
|
||||
},
|
||||
{
|
||||
nxt_string("host"),
|
||||
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];
|
||||
|
||||
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) {
|
||||
rule = nxt_http_route_rule_create(task, mp, mtcf.host, 1,
|
||||
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:
|
||||
return nxt_http_route_cookies(r, rule);
|
||||
|
||||
case NXT_HTTP_ROUTE_SCHEME:
|
||||
return nxt_http_route_scheme(r, rule);
|
||||
|
||||
default:
|
||||
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
|
||||
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',
|
||||
)
|
||||
|
||||
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__':
|
||||
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