From 26bf209b9956b52715fc3aa25edcf871f637b329 Mon Sep 17 00:00:00 2001 From: Eugene Paniot Date: Sat, 5 Nov 2022 00:28:14 +0000 Subject: [PATCH 1/3] Add trailing_slash http route option --- http/server.lua | 15 +++-- test/helpers.lua | 4 ++ .../integration/http_server_requests_test.lua | 66 +++++++++++++++++++ .../http_server_url_match_test.lua | 14 ++++ 4 files changed, 92 insertions(+), 7 deletions(-) diff --git a/http/server.lua b/http/server.lua index 243c15a..0c16965 100644 --- a/http/server.lua +++ b/http/server.lua @@ -981,10 +981,6 @@ local function httpd_stop(self) end local function match_route(self, method, route) - -- route must have '/' at the begin and end - if string.match(route, '.$') ~= '/' then - route = route .. '/' - end if string.match(route, '^.') ~= '/' then route = '/' .. route end @@ -995,8 +991,12 @@ local function match_route(self, method, route) local stash = {} for _, r in pairs(self.routes) do - if r.method == method or r.method == 'ANY' then - local m = { string.match(route, r.match) } + local sroute = route + if r.method == method or r.method == 'ANY' then + if r.trailing_slash and string.match(route, '.$') ~= '/' then + sroute = route .. '/' + end + local m = { string.match(sroute, r.match) } local nfit if #m > 0 then if #r.stash > 0 then @@ -1145,6 +1145,7 @@ local function add_route(self, opts, sub) end opts = extend({method = 'ANY'}, opts, false) + opts = extend({trailing_slash = true}, opts, false) local ctx local action @@ -1206,7 +1207,7 @@ local function add_route(self, opts, sub) table.insert(stash, name) end - if string.match(opts.match, '.$') ~= '/' then + if string.match(opts.match, '.$') ~= '/' and opts.trailing_slash then opts.match = opts.match .. '/' end if string.match(opts.match, '^.') ~= '/' then diff --git a/test/helpers.lua b/test/helpers.lua index cf8d243..6a86218 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -36,6 +36,10 @@ helpers.cfgserv = function(opts) :route({path = '/test', file = 'test.html.el' }, function(cx) return cx:render({ title = 'title: 123' }) end) + :route({path = '/trailing_slash_f/a/b/*c', trailing_slash = false}, + function(req) return req:render({text = req:stash("c")}) end) + :route({path = '/trailing_slash_t/a/b/*c', trailing_slash = true}, + function(req) return req:render({text = req:stash("c")}) end) return httpd end diff --git a/test/integration/http_server_requests_test.lua b/test/integration/http_server_requests_test.lua index 753b092..13ca1e2 100644 --- a/test/integration/http_server_requests_test.lua +++ b/test/integration/http_server_requests_test.lua @@ -417,3 +417,69 @@ g.test_content_type_header_without_render = function() t.assert_equals(r.status, 200) t.assert_equals(r.headers['content-type'], 'text/plain; charset=utf-8', 'content-type header') end + +g.test_trailing_slash_f_get = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/c') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, 'c') +end + +g.test_trailing_slash_f_get_with_slash_at_begging = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b//c') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c') +end + +g.test_trailing_slash_f_get_with_slash_at_begging_and_end = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b//c/') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c/') +end + +g.test_trailing_slash_f_get_with_slash = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/c/') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, 'c/') +end + +g.test_trailing_slash_f_get_with_encoded_slash_begging = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/%2Fc') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c') +end + +g.test_trailing_slash_f_get_with_encoded_slash_begging_and_end = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/%2Fc%2F') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c/') +end + +g.test_trailing_slash_f_get_html = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/c.htm') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, 'c.htm') +end + +g.test_trailing_slash_f_get_long = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/c/d/e') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, 'c/d/e') +end + +g.test_trailing_slash_f_get_long_with_slash_end = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_f/a/b/c/d/e/') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, 'c/d/e/') +end + +g.test_trailing_slash_t_get_with_slash_at_begging_and_end = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_t/a/b//c/') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c') +end + +g.test_trailing_slash_t_get_with_encoded_slash_begging_and_end = function() + local r = http_client.get(helpers.base_uri .. '/trailing_slash_t/a/b/%2Fc%2F') + t.assert_equals(r.status, 200) + t.assert_equals(r.body, '/c') +end diff --git a/test/integration/http_server_url_match_test.lua b/test/integration/http_server_url_match_test.lua index 284e201..6c302d6 100644 --- a/test/integration/http_server_url_match_test.lua +++ b/test/integration/http_server_url_match_test.lua @@ -46,4 +46,18 @@ g.test_server_url_match = function() '-123-dea/1/2/3', '/abb-123-dea/1/2/3/cde') t.assert_equals(httpd:match('GET', '/banners/1wulc.z8kiy.6p5e3').stash.token, '1wulc.z8kiy.6p5e3', 'stash with dots') + + t.assert_equals(httpd:match('GET', '/trailing_slash_t/a/b/c').endpoint.path, '/trailing_slash_t/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_t/a/b/c').stash.c, 'c') + t.assert_equals(httpd:match('GET', '/trailing_slash_t/a/b//c/').endpoint.path, '/trailing_slash_t/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_t/a/b//c/').stash.c, '/c') + + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b/c').endpoint.path, '/trailing_slash_f/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b/c').stash.c, 'c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b//c').endpoint.path, '/trailing_slash_f/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b//c').stash.c, '/c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b//c/').endpoint.path, '/trailing_slash_f/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b//c/').stash.c, '/c/') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b/c.htm').endpoint.path, '/trailing_slash_f/a/b/*c') + t.assert_equals(httpd:match('GET', '/trailing_slash_f/a/b/c.htm').stash.c, 'c.htm') end From a4908c4df5eaf52b0c254379bf2ce8022657a89b Mon Sep 17 00:00:00 2001 From: Eugene Paniot Date: Sat, 5 Nov 2022 00:50:07 +0000 Subject: [PATCH 2/3] Update CHANGELOG --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c48b8ac..2201986 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +- Add `trailing_slash` http route option. + ## [1.3.0] - 2022-07-27 ### Changed From 1c6190849c104dcacf339acaa2a05d6200937495 Mon Sep 17 00:00:00 2001 From: Eugene Paniot Date: Fri, 18 Nov 2022 17:17:38 +0000 Subject: [PATCH 3/3] Remove extra line trailing whitespace --- http/server.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/http/server.lua b/http/server.lua index 0c16965..913b58d 100644 --- a/http/server.lua +++ b/http/server.lua @@ -992,7 +992,7 @@ local function match_route(self, method, route) for _, r in pairs(self.routes) do local sroute = route - if r.method == method or r.method == 'ANY' then + if r.method == method or r.method == 'ANY' then if r.trailing_slash and string.match(route, '.$') ~= '/' then sroute = route .. '/' end