Add redirect() method to add a redirect on a domain much like
in the Kore configuration file.
eg:
domain.redirect("^/account/(.*)$", 301, "https://site/account/$1")
It was hardcoded that if KORE_USE_PYTHON was defined we would
look at the passed argument on the command-line as the python
script or module to be run.
This won't work when adding more runtimes.
So instead call a kore_runtime_resolve() function that in
turn calls each available runtime its resolve function.
That resolve function will check if its a script / module
that it can load, and if so will load it.
This way we can remove all those KORE_USE_PYTHON blocks in the
Kore startup path and we pave the way for lua.
Allow passing of an env keyword, allowing you to set environment variables
that may be required by the subprocess.
The env keyword must be a list with correctly formed environment variables.
eg:
proc = kore.proc("/bin/myproc",
env=[
"LD_LIBRARY_PATH=/my/path"
]
)
The _PyInterpreterFrame_GetLine() is hidden in dynamic libs so
roll our own variant of it.
Shuffle the old code so we always end up calling python_resolve_frame_line()
no matter the Python version.
In the upcoming Python 3.11 release the PyCoroObject no longer
has a full PyFrameObject, but instead their internal frame
struct _PyInterpreterFrame. Use that when we are building
against 3.11 or higher so we can still provide useful tracing
functionality (and so that it builds).
The crl keyword is parsed when the client_verify keyword has been set.
eg:
kore.domain("kore.io", cert="cert.pem", key="key.pem",
client_verify="cacert.pem", verify_depth=1, crl="crl.pem")
This commit introduces the ability to add authenticators to filemaps.
Just like in normal routes, the authenticators will be resolved first
before allowing access to the filemap entries.
Configuration wise, the authenticator is an optional value after the
filemap config directive:
filemap / webroot myauth
In the Python API you can now pass the authenticator for a filemap entry
but turning the value of the filemap into a tuple with the first entry
being the path and the second being the auth dict:
AUTH AUTH={
"type": "cookie",
"value": "cookiename",
"redirect": "/auth/",
"verify": verify_cookie
}
domain.filemaps({
"/css/": "webroot/css",
"/secret/": ("webroot/secret", AUTH)
})
The coroutines results are now relayed back via PyIter_Send() and
no longer obtainable via _PyGen_FetchStopIterationValue().
This means that our kore.gather() would not be able to return any
values from any of the coroutines it governed.
Fix this by saving the object returned in PyIter_Send() and using it
later in pygather_reap_coro().
Python 3.10.x its PyIter_Send() will return PYGEN_ERROR if the
generator returned (as opposed to yielding) if the result returned
is Py_None and no argument was given to PyIter_Send(). Which is counter
intuitive since it seems it should give us a PYGEN_RETURN as per its
documentation.
It also no longer sets PyExc_StopIteration in this case so we cannot depend
on that anymore to figure out if a coroutine has finished.
This caused Kore to respond with a 500 immediately after coroutines
ran to completion as it was looking for the PyExc_StopIteration exception.
Fix this by simply doing another check if an exception happened before
we enter the code path where Kore would spew the 500.
The cmsghdr contains a length (cmsg_len) which indicates the length
of the data in combination with the cmsghdr length itself.
Remove the length of the cmsghdr before passing it back up to callers
so they don't need to bother with it.
This also fixes a mistake where we ended up copying extra data
from the ancdata buffer that was unintended.
The whole while (cnt-- >= 0) idiom is busted since cnt started
at 0 and if the first call to PyUnicode_FromStringAndSize() fails
then we're attempting to access -1.
This commit adds improved hooks for Python and a new signal delivery hook.
For the Python API kore_worker_configure() and kore_worker_teardown() had
to be implemented before this commit. Now one can create a workerstart
and workerend method in their koreapp as those will be called when
they exist.
The new signal hook is either kore_worker_signal() or koreapp.signal.
This new hook is called after the worker event code handles the received
signal itself first.
With this commit there is also a new kore_signal_trap() API call allowing
you to more easily trap new signals. This API also also exported to the
Python part of the code under kore.sigtrap()
Adding the hooks keyword with a dictionary attached to specify
the relevant hooks will hook them for the given route.
Eg:
domain.route("/", self.index, methods=["get"],
hooks={
"on_free": self.request_free
}
)
These are the same hooks available via a normal Kore route configuration.
This dictionary for now only contains the subject and issuer names
from the client certificate (if one was provided) with their
X509_NAME components.
Eg:
{
"issuer": {
"C": "SE",
"O": "kore autogen: x509name-test",
"CN": "localhost"
},
"subject": {
"C": "SE",
"O": "kore autogen: x509name-test",
"CN": "localhost"
}
}
When a kore.socket() is closed from any coroutine, make sure any other
coroutines waiting on events on the socket are awoken so they properly
can return errors.
Routes are now configured in a context per route:
route /path {
handler handler_name
methods get post head
validate qs:get id v_id
}
All route related configurations are per-route, allowing multiple
routes for the same path (for different methods).
The param context is removed and merged into the route context now
so that you use the validate keyword to specify what needs validating.
Starting with the privsep config, this commit changes the following:
- Removes the root, runas, keymgr_root, keymgr_runas, acme_root and
acme_runas configuration options.
Instead these are now configured via a privsep configuration context:
privsep worker {
root /tmp
runas nobody
}
This is also configurable via Python using the new kore.privsep() method:
kore.privsep("worker", root="/tmp", runas="nobody", skip=["chroot"])
Tied into this we also better handle worker startup:
- Per worker process, wait until it signalled it is ready.
- If a worker fails at startup, display its last log lines more clearly.
- Don't start acme process if no domain requires acme.
- Remove each process its individual startup log message in favour
of a generalized one that displays its PID, root and user.
- At startup, log the kore version and built-ins in a nicer way.
- The worker processes now check things they need to start running
before signaling they are ready (such as access to CA certs for
TLS client authentication).
We always called kore_pgsql_query_param_fields() regardless if the
params keyword was specified or not, instead only use it if actual
parameters have been given.
Otherwise use the kore_pgsql_query() function directly to execute the query.
Now you can set curlopt on kore.httpclient at both the
global httpclient object level and individual requests.
Eg:
client = kore.httpclient("https://kore.io",
curlopt={
kore.CURLOPT_VERBOSE: 1
}
)
status, body = await client.get(
curlopt={
kore.CURLOPT_VERBOSE: 0
}
)