From: Marek VavruĊĦa Date: Wed, 21 Mar 2018 22:57:19 +0000 (-0700) Subject: http: allow loading custom endpoints to http X-Git-Tag: v2.4.0~30^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f46a32627ee0e2d09e89b02476822ca7dbcc55e8;p=thirdparty%2Fknot-resolver.git http: allow loading custom endpoints to http Previously the module was created on configuration time, so it wasn't possible to inject custom endpoints to the default interface. --- diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 732e7ff69..d24adfb32 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -282,6 +282,7 @@ knot_mm_t *kr_resolve_pool(struct kr_request *); struct kr_query *kr_rplan_push(struct kr_rplan *, struct kr_query *, const knot_dname_t *, uint16_t, uint16_t); int kr_rplan_pop(struct kr_rplan *, struct kr_query *); struct kr_query *kr_rplan_resolved(struct kr_rplan *); +struct kr_query *kr_rplan_last(struct kr_rplan *); int kr_nsrep_set(struct kr_query *, size_t, const struct sockaddr *); uint32_t kr_rand_uint(uint32_t); int kr_make_query(struct kr_query *query, knot_pkt_t *pkt); diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index 8132430d4..f06a742b1 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -141,6 +141,7 @@ EOF kr_rplan_push kr_rplan_pop kr_rplan_resolved + kr_rplan_last # Nameservers kr_nsrep_set # Utils diff --git a/daemon/lua/kres.lua b/daemon/lua/kres.lua index f3f1b649b..4756bc419 100644 --- a/daemon/lua/kres.lua +++ b/daemon/lua/kres.lua @@ -702,6 +702,13 @@ ffi.metatype( kr_request_t, { if req.current_query == nil then return nil end return req.current_query end, + -- Return last query on the resolution plan + last = function(req) + assert(ffi.istype(kr_request_t, req)) + local query = C.kr_rplan_last(C.kr_resolve_plan(req)) + if query == nil then return end + return query + end, resolved = function(req) assert(ffi.istype(kr_request_t, req)) local qry = C.kr_rplan_resolved(C.kr_resolve_plan(req)) diff --git a/modules/http/README.rst b/modules/http/README.rst index e9414fc81..df21f5c4e 100644 --- a/modules/http/README.rst +++ b/modules/http/README.rst @@ -31,6 +31,7 @@ for starters? geoip = 'GeoLite2-City.mmdb' -- Optional, see -- e.g. https://dev.maxmind.com/geoip/geoip2/geolite2/ -- and install mmdblua library + endpoints = {}, } } @@ -142,7 +143,7 @@ In order to register a new service, simply add it to the table: .. code-block:: lua - http.endpoints['/health'] = {'application/json', + local on_health = {'application/json', function (h, stream) -- API call, return a JSON table return {state = 'up', uptime = 0} @@ -158,6 +159,12 @@ In order to register a new service, simply add it to the table: -- Finalize the WebSocket ws:close() end} + -- Load module + modules = { + http = { + endpoints = { ['/health'] = on_health } + } + } Then you can query the API endpoint, or tail the WebSocket using curl. @@ -200,7 +207,7 @@ the HTTP response code or send headers and body yourself. local value = 42 -- Expose the service - http.endpoints['/service'] = {'application/json', + local service = {'application/json', function (h, stream) -- Get request method and deal with it properly local m = h:get(':method') @@ -221,6 +228,12 @@ the HTTP response code or send headers and body yourself. return 405, 'Cannot do that' end end} + -- Load the module + modules = { + http = { + endpoints = { ['/service'] = service } + } + } In some cases you might need to send back your own headers instead of default provided by HTTP handler, you can do this, but then you have to return ``false`` to notify handler that it shouldn't try to generate diff --git a/modules/http/http.lua b/modules/http/http.lua index f12c8fad8..3cf8149d3 100644 --- a/modules/http/http.lua +++ b/modules/http/http.lua @@ -114,21 +114,27 @@ M.snippets = {} -- Serve known requests, for methods other than GET -- the endpoint must be a closure and not a preloaded string -local function serve(h, stream) +local function serve(endpoints, h, stream) local hsend = http_headers.new() local path = h:get(':path') - local entry = M.endpoints[path] + local entry = endpoints[path] if not entry then -- Accept top-level path match - entry = M.endpoints[path:match '^/[^/]*'] + entry = endpoints[path:match '^/[^/?]*'] end -- Unpack MIME and data - local mime, data, err + local data, mime, ttl, err if entry then - mime, data = unpack(entry) + mime = entry[1] + data = entry[2] + ttl = entry[4] end -- Get string data out of service endpoint if type(data) == 'function' then - data, err = data(h, stream) + local set_mime, set_ttl + data, err, set_mime, set_ttl = data(h, stream) + -- Override default endpoint mime/TTL + if set_mime then mime = set_mime end + if set_ttl then ttl = set_ttl end -- Handler doesn't provide any data if data == false then return end if type(data) == 'number' then return tostring(data), err end @@ -144,7 +150,6 @@ local function serve(h, stream) hsend:append(':status', '200') hsend:append('content-type', mime) hsend:append('content-length', tostring(#data)) - local ttl = entry and entry[4] if ttl then hsend:append('cache-control', string.format('max-age=%d', ttl)) end @@ -180,7 +185,7 @@ local function route(endpoints) ws:close() return else - local ok, err, reason = http_util.yieldable_pcall(serve, h, stream) + local ok, err, reason = http_util.yieldable_pcall(serve, endpoints, h, stream) if not ok or err then if err ~= '404' and verbose() then log('[http] %s %s: %s (%s)', m, path, err or '500', reason) @@ -357,7 +362,12 @@ function M.config(conf) error('[http] mmdblua library not found, please remove GeoIP configuration') end end - M.interface(conf.host, conf.port, M.endpoints, conf.cert, conf.key) + -- Add endpoints to default endpoints + local endpoints = conf.endpoints or {} + for k, v in pairs(M.endpoints) do + endpoints[k] = v + end + M.interface(conf.host, conf.port, endpoints, conf.cert, conf.key) end return M diff --git a/modules/http/http.test.lua b/modules/http/http.test.lua index 57525810a..a4f2a0a9e 100644 --- a/modules/http/http.test.lua +++ b/modules/http/http.test.lua @@ -11,6 +11,7 @@ else http = { port = 0, -- Select random port cert = false, + endpoints = { ['/test'] = {'text/custom', function () return 'hello' end} }, } } @@ -35,6 +36,11 @@ else same(code, 200, 'static page return 200 OK') ok(#body > 0, 'static page has non-empty body') same(mime, 'text/html', 'static page has text/html content type') + -- custom endpoint + code, body, mime = http_get(uri .. '/test') + same(code, 200, 'custom page return 200 OK') + same(body, 'hello', 'custom page has non-empty body') + same(mime, 'text/custom', 'custom page has custom content type') -- non-existent page code = http_get(uri .. '/badpage') same(code, 404, 'non-existent page returns 404')