]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
doc: move custom HTTP services to Devel section
authorPetr Špaček <petr.spacek@nic.cz>
Wed, 8 Jan 2020 08:15:12 +0000 (09:15 +0100)
committerTomas Krizek <tomas.krizek@nic.cz>
Wed, 15 Jan 2020 09:38:18 +0000 (10:38 +0100)
doc/index.rst
doc/modules-http-custom-services.rst [new symlink]
modules/http/README.rst
modules/http/custom_services.rst [new file with mode: 0644]

index cac125b597f4fc6ec2d6f9f472bcbf3e4d479cef..c2f178a753a1febbce13b40edc4626850896f3ed 100644 (file)
@@ -43,6 +43,7 @@ and it provides a state-machine like API for extensions.
    :maxdepth: 2
 
    build
+   modules-http-custom-services
    lib
    modules_api
    worker_api
diff --git a/doc/modules-http-custom-services.rst b/doc/modules-http-custom-services.rst
new file mode 120000 (symlink)
index 0000000..5cbc7ec
--- /dev/null
@@ -0,0 +1 @@
+../modules/http/custom_services.rst
\ No newline at end of file
index b1777143f910bf3c4be116565cc3bd72a1658124..fa7124a31d4d5eb53c319fcb76391522b9d7d2ad 100644 (file)
@@ -133,142 +133,6 @@ The HTTP module has several built-in services to use.
  "``/trace/:name/:type``", "Tracking", ":ref:`Trace resolution <mod-http-trace>` of a DNS query and return the verbose logs."
  "``/doh``", "DNS-over-HTTP", ":rfc:`8484` endpoint, see :ref:`mod-http-doh`."
 
-.. _mod-http-custom-endpoint:
-
-How to expose custom services over HTTP
----------------------------------------
-
-Each kind of endpoint provides table of HTTP endpoints, and the default table
-can be replaced using ``http.config()`` configuration call
-which allows your to provide your own HTTP endpoints.
-
-It contains tables describing a triplet - ``{mime, on_serve, on_websocket}``.
-In order to register a new `webmgmt` HTTP endpoint
-add the new endpoint description to respective table:
-
-
-.. code-block:: lua
-
-       -- custom function to handle HTTP /health requests
-       local on_health = {'application/json',
-       function (h, stream)
-               -- API call, return a JSON table
-               return {state = 'up', uptime = 0}
-       end,
-       function (h, ws)
-               -- Stream current status every second
-               local ok = true
-               while ok do
-                       local push = tojson('up')
-                       ok = ws:send(tojson({'up'}))
-                       require('cqueues').sleep(1)
-               end
-               -- Finalize the WebSocket
-               ws:close()
-       end}
-
-       modules.load('http')
-       -- copy all existing webmgmt endpoints
-       my_mgmt_endpoints = http.configs._builtin.webmgmt.endpoints
-       -- add custom endpoint to the copy
-       my_mgmt_endpoints['/health'] = on_health
-       -- use custom HTTP configuration for webmgmt
-       http.config({
-               endpoints = my_mgmt_endpoints
-       }, 'webmgmt')
-
-Then you can query the API endpoint, or tail the WebSocket using curl.
-
-.. code-block:: bash
-
-       $ curl -k https://localhost:8453/health
-       {"state":"up","uptime":0}
-       $ curl -k -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: localhost:8453/health"  -H "Sec-Websocket-Key: nope" -H "Sec-Websocket-Version: 13" https://localhost:8453/health
-       HTTP/1.1 101 Switching Protocols
-       upgrade: websocket
-       sec-websocket-accept: eg18mwU7CDRGUF1Q+EJwPM335eM=
-       connection: upgrade
-
-       ?["up"]?["up"]?["up"]
-
-Since the stream handlers are effectively coroutines, you are free to keep state
-and yield using `cqueues library <http://www.25thandclement.com/~william/projects/cqueues.html>`_.
-
-This is especially useful for WebSockets, as you can stream content in a simple loop instead of
-chains of callbacks.
-
-Last thing you can publish from modules are *"snippets"*. Snippets are plain pieces of HTML code that are rendered at the end of the built-in webpage. The snippets can be extended with JS code to talk to already
-exported restful APIs and subscribe to WebSockets.
-
-.. code-block:: lua
-
-       http.snippets['/health'] = {'Health service', '<p>UP!</p>'}
-
-How to expose custom RESTful services
--------------------------------------
-
-A RESTful service is likely to respond differently to different type of methods and requests,
-there are three things that you can do in a service handler to send back results.
-First is to just send whatever you want to send back, it has to respect MIME type that the service
-declared in the endpoint definition. The response code would then be ``200 OK``, any non-string
-responses will be packed to JSON. Alternatively, you can respond with a number corresponding to
-the HTTP response code or send headers and body yourself.
-
-.. code-block:: lua
-
-       -- Our upvalue
-       local value = 42
-
-       -- Expose the service
-       local service = {'application/json',
-       function (h, stream)
-               -- Get request method and deal with it properly
-               local m = h:get(':method')
-               local path = h:get(':path')
-               log('[service] method %s path %s', m, path)
-               -- Return table, response code will be '200 OK'
-               if m == 'GET' then
-                       return {key = path, value = value}
-               -- Save body, perform check and either respond with 505 or 200 OK
-               elseif m == 'POST' then
-                       local data = stream:get_body_as_string()
-                       if not tonumber(data) then
-                               return 500, 'Not a good request'
-                       end
-                       value = tonumber(data)
-               -- Unsupported method, return 405 Method not allowed
-               else
-                       return 405, 'Cannot do that'
-               end
-       end}
-       modules.load('http')
-       http.config({
-               endpoints = { ['/service'] = service }
-       }, 'myservice')
-       -- do not forget to create socket of new kind using
-       -- net.listen(..., { kind = 'myservice' })
-       -- or configure systemd socket kresd-myservice.socket
-
-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
-a response.
-
-.. code-block:: lua
-
-       local headers = require('http.headers')
-       function (h, stream)
-               -- Send back headers
-               local hsend = headers.new()
-               hsend:append(':status', '200')
-               hsend:append('content-type', 'binary/octet-stream')
-               assert(stream:write_headers(hsend, false))
-               -- Send back data
-               local data = 'binary-data'
-               assert(stream:write_chunk(data, true))
-               -- Disable default handler action
-               return false
-       end
-
 Dependencies
 ------------
 
diff --git a/modules/http/custom_services.rst b/modules/http/custom_services.rst
new file mode 100644 (file)
index 0000000..970101d
--- /dev/null
@@ -0,0 +1,143 @@
+.. _mod-http-custom-endpoint:
+
+Custom HTTP services
+====================
+
+This chapter describes how to create custom HTTP services inside Knot Resolver.
+Please read HTTP module basics in chapter :ref:`mod-http` before continuing.
+
+Each network address+protocol+port combination configured using :func:`net.listen`
+is associated with *kind* of endpoint, e.g. ``doh`` or ``webmgmt``.
+
+Each of these *kind* names is associated with table of HTTP endpoints,
+and the default table can be replaced using ``http.config()`` configuration call
+which allows your to provide your own HTTP endpoints.
+
+Items in the table of HTTP endpoints are small tables describing a triplet
+- ``{mime, on_serve, on_websocket}``.
+In order to register a new service in ``webmgmt`` *kind* of HTTP endpoint
+add the new endpoint description to respective table:
+
+.. code-block:: lua
+
+       -- custom function to handle HTTP /health requests
+       local on_health = {'application/json',
+       function (h, stream)
+               -- API call, return a JSON table
+               return {state = 'up', uptime = 0}
+       end,
+       function (h, ws)
+               -- Stream current status every second
+               local ok = true
+               while ok do
+                       local push = tojson('up')
+                       ok = ws:send(tojson({'up'}))
+                       require('cqueues').sleep(1)
+               end
+               -- Finalize the WebSocket
+               ws:close()
+       end}
+
+       modules.load('http')
+       -- copy all existing webmgmt endpoints
+       my_mgmt_endpoints = http.configs._builtin.webmgmt.endpoints
+       -- add custom endpoint to the copy
+       my_mgmt_endpoints['/health'] = on_health
+       -- use custom HTTP configuration for webmgmt
+       http.config({
+               endpoints = my_mgmt_endpoints
+       }, 'webmgmt')
+
+Then you can query the API endpoint, or tail the WebSocket using curl.
+
+.. code-block:: bash
+
+       $ curl -k https://localhost:8453/health
+       {"state":"up","uptime":0}
+       $ curl -k -i -N -H "Connection: Upgrade" -H "Upgrade: websocket" -H "Host: localhost:8453/health"  -H "Sec-Websocket-Key: nope" -H "Sec-Websocket-Version: 13" https://localhost:8453/health
+       HTTP/1.1 101 Switching Protocols
+       upgrade: websocket
+       sec-websocket-accept: eg18mwU7CDRGUF1Q+EJwPM335eM=
+       connection: upgrade
+
+       ?["up"]?["up"]?["up"]
+
+Since the stream handlers are effectively coroutines, you are free to keep state
+and yield using `cqueues library <http://www.25thandclement.com/~william/projects/cqueues.html>`_.
+
+This is especially useful for WebSockets, as you can stream content in a simple loop instead of
+chains of callbacks.
+
+Last thing you can publish from modules are *"snippets"*. Snippets are plain pieces of HTML code
+that are rendered at the end of the built-in webpage. The snippets can be extended with JS code to talk to already
+exported restful APIs and subscribe to WebSockets.
+
+.. code-block:: lua
+
+       http.snippets['/health'] = {'Health service', '<p>UP!</p>'}
+
+Custom RESTful services
+-----------------------
+
+A RESTful service is likely to respond differently to different type of methods and requests,
+there are three things that you can do in a service handler to send back results.
+First is to just send whatever you want to send back, it has to respect MIME type that the service
+declared in the endpoint definition. The response code would then be ``200 OK``, any non-string
+responses will be packed to JSON. Alternatively, you can respond with a number corresponding to
+the HTTP response code or send headers and body yourself.
+
+.. code-block:: lua
+
+       -- Our upvalue
+       local value = 42
+
+       -- Expose the service
+       local service = {'application/json',
+       function (h, stream)
+               -- Get request method and deal with it properly
+               local m = h:get(':method')
+               local path = h:get(':path')
+               log('[service] method %s path %s', m, path)
+               -- Return table, response code will be '200 OK'
+               if m == 'GET' then
+                       return {key = path, value = value}
+               -- Save body, perform check and either respond with 505 or 200 OK
+               elseif m == 'POST' then
+                       local data = stream:get_body_as_string()
+                       if not tonumber(data) then
+                               return 500, 'Not a good request'
+                       end
+                       value = tonumber(data)
+               -- Unsupported method, return 405 Method not allowed
+               else
+                       return 405, 'Cannot do that'
+               end
+       end}
+       modules.load('http')
+       http.config({
+               endpoints = { ['/service'] = service }
+       }, 'myservice')
+       -- do not forget to create socket of new kind using
+       -- net.listen(..., { kind = 'myservice' })
+       -- or configure systemd socket kresd-myservice.socket
+
+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
+a response.
+
+.. code-block:: lua
+
+       local headers = require('http.headers')
+       function (h, stream)
+               -- Send back headers
+               local hsend = headers.new()
+               hsend:append(':status', '200')
+               hsend:append('content-type', 'binary/octet-stream')
+               assert(stream:write_headers(hsend, false))
+               -- Send back data
+               local data = 'binary-data'
+               assert(stream:write_chunk(data, true))
+               -- Disable default handler action
+               return false
+       end
+