doc: add section on security and misc fixes
Co-authored-by: Roberto Abdelkader Martínez Pérez <robertomartinezp@gmail.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
Kapow! HTTP Interfaces
|
||||
======================
|
||||
|
||||
`kapow server` sets up three HTTP server interfaces, each with a distinct and
|
||||
clear purpose.
|
||||
|
||||
User Interface
|
||||
--------------
|
||||
|
||||
The User HTTP interface is used to serve final user requests.
|
||||
|
||||
By default it binds to address ``0.0.0.0`` and port ``8080``, but can be changed via
|
||||
the ``--bind`` flag.
|
||||
|
||||
|
||||
Control Interface
|
||||
-----------------
|
||||
|
||||
The Control HTTP interface is used by the command `kapow route` to
|
||||
administer the list of system routes.
|
||||
|
||||
By default it binds to address ``127.0.0.1`` and port ``8081``, but can be changed
|
||||
via the ``--control-bind`` flag.
|
||||
|
||||
|
||||
Data Interface
|
||||
--------------
|
||||
|
||||
The Data HTTP interface is used by the commands ``kapow get`` and ``kapow
|
||||
set`` to exchange the data for a particular request.
|
||||
|
||||
By default it binds to address ``127.0.0.1`` and port ``8082``, but can be changed
|
||||
via the ``--data-bind`` flag.
|
||||
@@ -0,0 +1,31 @@
|
||||
Philosophy
|
||||
==========
|
||||
|
||||
|
||||
Single Static Binary
|
||||
--------------------
|
||||
|
||||
- Deployment is then as simple as it gets.
|
||||
|
||||
- Docker-friendly.
|
||||
|
||||
|
||||
Shell Agnostic
|
||||
--------------
|
||||
|
||||
- Kapow! knows nothing, and makes no assumptions, about the shell you are using.
|
||||
It only spawns executables.
|
||||
|
||||
- You are free to implement a client to the Data API directly if you are so
|
||||
inclined. The spec provides all the necessary details.
|
||||
|
||||
|
||||
Not a Silver Bullet
|
||||
-------------------
|
||||
|
||||
You should not use Kapow! if your project requires complex business logic.
|
||||
|
||||
If you try to encode business logic in a shell script, you will **deeply**
|
||||
regret it.
|
||||
|
||||
Kapow! is designed for automating simple stuff.
|
||||
@@ -0,0 +1,62 @@
|
||||
Request Life Cycle
|
||||
==================
|
||||
|
||||
This section describes the sequence of events happening for each request
|
||||
answered by the `User HTTP Interface`.
|
||||
|
||||
.. image:: ../_static/request_life_cycle.png
|
||||
|
||||
|
||||
1. request
|
||||
----------
|
||||
|
||||
The user makes a request to the `User HTTP Interface`.
|
||||
|
||||
- The request is matched against the route table
|
||||
|
||||
- ``kapow`` provides a `HANDLER_ID` to identify this request and don't mix it
|
||||
with other requests that could be running concurrently.
|
||||
|
||||
2. spawn
|
||||
--------
|
||||
|
||||
``kapow`` spawns the executable specified as entrypoint in the matching
|
||||
route.
|
||||
|
||||
The default entrypoint is ``/bin/sh``; we'll explain this workflow for now.
|
||||
|
||||
The spawned entrypoint is run with the following variables added to its
|
||||
environment:
|
||||
|
||||
- ``KAPOW_HANDLER_ID``: Containing the `HANDLER_ID`
|
||||
- ``KAPOW_DATAAPI_URL``: With the URL of the `Data HTTP Interface`
|
||||
- ``KAPOW_CONTROLAPI_URL``: With the URL of the `Control HTTP Interface`
|
||||
|
||||
3. ``kapow set /response/body banana``
|
||||
--------------------------------------
|
||||
|
||||
During the lifetime of the shell, the request and response resources are
|
||||
available via these commands:
|
||||
|
||||
- ``kapow get /request/...``
|
||||
|
||||
- ``kapow set /response/...``
|
||||
|
||||
These commands use the aforementioned environment variables to read data
|
||||
from the user request and to write the response. They accept data
|
||||
either as arguments or from ``stdin``.
|
||||
|
||||
4. exit
|
||||
-------
|
||||
|
||||
The shell dies.
|
||||
|
||||
5. response
|
||||
-----------
|
||||
|
||||
``kapow`` finalizes the original request.
|
||||
|
||||
|
||||
.. todo::
|
||||
|
||||
link to resource tree
|
||||
@@ -0,0 +1,353 @@
|
||||
The `Kapow!` Resource Tree
|
||||
==========================
|
||||
|
||||
This is the model that Kapow! uses to expose the internals of the user request
|
||||
being serviced.
|
||||
|
||||
|
||||
We use this tree to get access to any data that comes in the request,
|
||||
as well as to compose the response.
|
||||
|
||||
We access the resource tree easily with the ``kapow set`` and ``kapow get``
|
||||
subcommands.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
/
|
||||
│
|
||||
├─ request
|
||||
│ ├──── method Used HTTP Method (GET, POST)
|
||||
│ ├──── host Host part of the URL
|
||||
│ ├──── path Complete URL path (URL-unquoted)
|
||||
│ ├──── matches
|
||||
│ │ └──── <name> Previously matched URL path parts
|
||||
│ ├──── params
|
||||
│ │ └──── <name> URL parameters (after the "?" symbol)
|
||||
│ ├──── headers
|
||||
│ │ └──── <name> HTTP request headers
|
||||
│ ├──── cookies
|
||||
│ │ └──── <name> HTTP request cookie
|
||||
│ ├──── form
|
||||
│ │ └──── <name> Value of the form field with name <name>
|
||||
│ ├──── files
|
||||
│ │ └──── <name>
|
||||
│ │ └──── filename Original file name of the file uploaded in the form field <name>
|
||||
│ │ └──── content The contents of the file uploaded in the form field <name>
|
||||
│ └──── body HTTP request body
|
||||
│
|
||||
└─ response
|
||||
├──── status HTTP status code
|
||||
├──── headers
|
||||
│ └──── <name> HTTP response headers
|
||||
├──── cookies
|
||||
│ └──── <name> HTTP request cookie
|
||||
└──── body Response body
|
||||
|
||||
Resources
|
||||
---------
|
||||
|
||||
``/request/method`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The HTTP method of the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -X POST http://kapow.example:8080
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/method
|
||||
POST
|
||||
|
||||
|
||||
``/request/host`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``Host`` header as defined in the HTTP/1.1 spec of the incoming
|
||||
request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl http://kapow.example:8080
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/host
|
||||
kapow.example
|
||||
|
||||
|
||||
``/request/path`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the path substring of the URL.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl http://kapow.example:8080/foo/bar?qux=1
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/path
|
||||
/foo/bar
|
||||
|
||||
``/request/matches/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the part of the URL captured by the pattern ``name``.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
For a route defined like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow route add /foo/{mymatch}/bar
|
||||
|
||||
if the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl http://kapow.example:8080/foo/1234/bar
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/matches/mymatch
|
||||
1234
|
||||
|
||||
``/request/params/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the URL parameter ``name``
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl http://kapow.example:8080/foo?myparam=bar
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/params/myparam
|
||||
myparam
|
||||
|
||||
|
||||
``/request/headers/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the HTTP header ``name`` of the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -H X-My-Header=Bar http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/headers/X-My-Header
|
||||
Bar
|
||||
|
||||
|
||||
``/request/cookies/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the HTTP cookie ``name`` of the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl --cookie "MYCOOKIE=Bar" http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/cookies/MYCOOKIE
|
||||
Bar
|
||||
|
||||
``/request/form/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the field ``name`` of the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -F -d myfield=foo http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/form/myfield
|
||||
foo
|
||||
|
||||
|
||||
``/request/files/<name>/filename`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the name of the file uploaded through the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -F -d myfile=@filename.txt http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/files/myfile/filename
|
||||
filename.txt
|
||||
|
||||
|
||||
``/request/files/<name>/content`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contents of the file that is being uploaded in the incoming request.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl -F -d myfile=@filename.txt http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/files/myfile/content
|
||||
...filename.txt contents...
|
||||
|
||||
|
||||
``/request/body`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Raw contents of the incoming request HTTP body.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If the user runs:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ curl --data-raw foobar http://kapow.example:8080/
|
||||
|
||||
then, when handling the request:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow get /request/body
|
||||
foobar
|
||||
|
||||
|
||||
``/response/status`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the status code given in the user response.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If during the request handling:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow set /response/status 418
|
||||
|
||||
then the response will have the status code ``418 I am a Teapot``.
|
||||
|
||||
|
||||
``/response/headers/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the header ``name`` in the user response.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If during the request handling:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow set /response/headers/X-My-Header Foo
|
||||
|
||||
then the response will contain an HTTP header named ``X-My-Header`` with
|
||||
value ``Foo``.
|
||||
|
||||
|
||||
``/response/cookies/<name>`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the cookie ``name`` that will be set to the user
|
||||
response.
|
||||
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If during the request handling:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow set /response/cookies/MYCOOKIE Foo
|
||||
|
||||
then the response will set the cookie ``MYCOOKIE`` to the user in
|
||||
following requests.
|
||||
|
||||
|
||||
``/response/body`` Resource
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Contains the value of the response HTTP body.
|
||||
|
||||
**Sample Usage**
|
||||
|
||||
If during the request handling:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow set /response/body foobar
|
||||
|
||||
then the response will contain ``foobar`` in the body.
|
||||
@@ -0,0 +1,14 @@
|
||||
Route Matching
|
||||
==============
|
||||
|
||||
Kapow! maintains a route table with a list of routes as provided by the user,
|
||||
and uses it to determine which handler should an incoming request be dispatched
|
||||
to.
|
||||
|
||||
.. todo::
|
||||
|
||||
link routes to its section
|
||||
|
||||
Each incoming request is matched against the routes in the route table in
|
||||
strict order, for each route in the route table, the criteria are checked.
|
||||
If the request does not match, the next route in the route list is examined.
|
||||
@@ -0,0 +1,124 @@
|
||||
Routes
|
||||
======
|
||||
|
||||
A Kapow! route specifies the matching criteria for an incoming request on
|
||||
the `User HTTP Interface`, and the details to handle it.
|
||||
|
||||
Kapow! implements a *route table* where all routes reside.
|
||||
|
||||
|
||||
A route can be set like this:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ kapow route add \
|
||||
-X POST \
|
||||
'/register/{username}' \
|
||||
-e '/bin/bash -c' \
|
||||
-c 'touch /var/lib/mydb/"$(kapow get /request/matches/username)"' \
|
||||
| jq
|
||||
{
|
||||
"id": "deadbeef-0d09-11ea-b18e-106530610c4d",
|
||||
"method": "POST",
|
||||
"url_pattern": "/register/{username}",
|
||||
"entrypoint": "/bin/bash -c",
|
||||
"command": "touch /var/lib/mydb/\"$(kapow get /request/matches/username)\""
|
||||
}
|
||||
|
||||
Let's use this example to discuss its elements.
|
||||
|
||||
|
||||
Elements
|
||||
--------
|
||||
|
||||
``id`` Route Element
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Uniquely identifies each route. It is used for instance by ``kapow route remove
|
||||
<route_id>``.
|
||||
|
||||
.. note::
|
||||
|
||||
The current implementation of Kapow! autogenerates a `UUID` for this field.
|
||||
In the future the use will be able to specify a custom value.
|
||||
|
||||
|
||||
``method`` Route Element
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Specifies the HTTP method for the route to match the incoming request.
|
||||
|
||||
The route shown above will only match a ``POST`` request.
|
||||
|
||||
|
||||
``url_pattern`` Route Element
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It matches the `path` component of the `URL` of the incoming request.
|
||||
|
||||
It can contain regex placeholders for easily capturing fragments of the path.
|
||||
|
||||
In the route shown above, a request with a URL ``/register/joe`` would match,
|
||||
assigning `joe` to the placeholder ``username``.
|
||||
|
||||
Kapow! leverages Gorilla Mux for managing routes. For the full story, see
|
||||
https://github.com/gorilla/mux#examples
|
||||
|
||||
|
||||
``entrypoint`` Route Element
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This sets the executable to be spawned, along with any arguments required.
|
||||
|
||||
In the route shown above, the entrypoint that will be run is ``/bin/bash -c``,
|
||||
which is an incomplete recipe. It is completed by the `command` element.
|
||||
|
||||
.. todo::
|
||||
|
||||
link to command below
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
The semantics of this element closely match `Docker`'s ``ENTRYPOINT`` directive.
|
||||
|
||||
.. todo::
|
||||
|
||||
link to Docker docu
|
||||
|
||||
|
||||
``command`` Route Element
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This is an optional last argument to be passed to the ``entrypoint``.
|
||||
|
||||
In the route shown above, it completes the `entrypoint` to form the final
|
||||
incantation to be executed:
|
||||
|
||||
.. todo::
|
||||
|
||||
link to entrypoint above
|
||||
|
||||
.. code-block::
|
||||
|
||||
/bin/bash -c 'touch /var/lib/mydb/"$(kapow get /request/matches/username)"'
|
||||
|
||||
.. note::
|
||||
|
||||
The semantics of this element closely match `Docker`'s ``COMMAND`` directive.
|
||||
|
||||
.. todo::
|
||||
|
||||
link to Docker docu
|
||||
|
||||
|
||||
Matching Algorithm
|
||||
------------------
|
||||
|
||||
`Kapow!` leverages Gorilla Mux for this task. You can see the gory details in
|
||||
their documentation.
|
||||
|
||||
|
||||
.. todo::
|
||||
|
||||
link to Gorilla Mux docu
|
||||
Reference in New Issue
Block a user