summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAxel Duch <axel.duch@nginx.com>2019-07-24 13:47:35 +0300
committerAxel Duch <axel.duch@nginx.com>2019-07-24 13:47:35 +0300
commit7785c96c1aea16dee0ec17403fda01b4f5ba41b3 (patch)
tree9abd736f0cfbfd6bea13685b1849ca4565dd1ce8
parentb1165d2edc99daf8eef0e092e4ed6dcee9bce252 (diff)
downloadunit-7785c96c1aea16dee0ec17403fda01b4f5ba41b3.tar.gz
unit-7785c96c1aea16dee0ec17403fda01b4f5ba41b3.tar.bz2
Added routing based on request scheme.
Scheme matches exact string “http” or “https”.
-rw-r--r--src/nxt_conf_validation.c29
-rw-r--r--src/nxt_h1proto.c21
-rw-r--r--src/nxt_http.h2
-rw-r--r--src/nxt_http_request.c1
-rw-r--r--src/nxt_http_route.c36
-rw-r--r--test/test_routing.py94
-rw-r--r--test/test_routing_tls.py58
7 files changed, 221 insertions, 20 deletions
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index bee82dd4..45c0eb41 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -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,
@@ -820,6 +827,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)
{
diff --git a/src/nxt_h1proto.c b/src/nxt_h1proto.c
index 3a822042..6bc6c7ee 100644
--- a/src/nxt_h1proto.c
+++ b/src/nxt_h1proto.c
@@ -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)
diff --git a/src/nxt_http.h b/src/nxt_http.h
index 835cf66d..7398c9c1 100644
--- a/src/nxt_http.h
+++ b/src/nxt_http.h
@@ -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[];
diff --git a/src/nxt_http_request.c b/src/nxt_http_request.c
index 1265c186..ce088acb 100644
--- a/src/nxt_http_request.c
+++ b/src/nxt_http_request.c
@@ -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);
}
}
diff --git a/src/nxt_http_route.c b/src/nxt_http_route.c
index ade44666..0b665573 100644
--- a/src/nxt_http_route.c
+++ b/src/nxt_http_route.c
@@ -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);
@@ -277,6 +281,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,
offsetof(nxt_http_route_match_conf_t, host),
@@ -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;
}
@@ -1331,6 +1355,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)
{
nxt_array_t *cookies;
diff --git a/test/test_routing.py b/test/test_routing.py
index 40d9f786..6073877d 100644
--- a/test/test_routing.py
+++ b/test/test_routing.py
@@ -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()
diff --git a/test/test_routing_tls.py b/test/test_routing_tls.py
new file mode 100644
index 00000000..433a303e
--- /dev/null
+++ b/test/test_routing_tls.py
@@ -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()