]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
http: allow loading custom endpoints to http
authorMarek Vavruša <mvavrusa@cloudflare.com>
Wed, 21 Mar 2018 22:57:19 +0000 (15:57 -0700)
committerGrigorii Demidov <grigorii.demidov@nic.cz>
Thu, 31 May 2018 14:54:10 +0000 (16:54 +0200)
Previously the module was created on configuration time, so it wasn't
possible to inject custom endpoints to the default interface.

daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
daemon/lua/kres.lua
modules/http/README.rst
modules/http/http.lua
modules/http/http.test.lua

index 732e7ff69115c1de556d7449902952ad78e9b99b..d24adfb32fb8236ca2822c091e02d16622a2cf3c 100644 (file)
@@ -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);
index 8132430d4d13a26eff2727a3d8a1bd61b507b6a4..f06a742b178d2a20bb8110e61a5a4d74f69d754c 100755 (executable)
@@ -141,6 +141,7 @@ EOF
        kr_rplan_push
        kr_rplan_pop
        kr_rplan_resolved
+       kr_rplan_last
 # Nameservers
        kr_nsrep_set
 # Utils
index f3f1b649b6dbe835d891d2711fdc49f1be9c180b..4756bc419cec36fd5ad6eeae7d7f53156f03279f 100644 (file)
@@ -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))
index e9414fc81df04b3b894b709bfe3339808e92d229..df21f5c4e3128c31fd9ba451df2b57103475774c 100644 (file)
@@ -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
index f12c8fad835ff77774947c87713f95c7cb44142b..3cf8149d32b6b6718ca1d7e6edf3364cbdab2aa4 100644 (file)
@@ -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
index 57525810a31024697c0f73facffd248ebb81db7d..a4f2a0a9eccdb45d7e2a0a997f25c4810517d021 100644 (file)
@@ -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')