This will place the required sources for building
single binary builds under $PREFIX/share/kore.
The kodev utility will now pickup this KORE_SOURCE path automatically
unless another one is given via the conf/build.conf file or the KORE_SOURCE
environment path.
Without it python_curlopt.h might not be available at the right
time when using something like make -j4:
src/python.c:50:10: fatal error: 'python_curlopt.h' file not found
^~~~~~~~~~~~~~~~~~
1 error generated.
Signed-off-by: Tobias Kortkamp <t@tobik.me>
Kore already exposed parts of this via the kore.httpclient() method but
this commit takes it a bit further and exposes the libcurl interface
completely (including the setopt options).
tldr:
handle = kore.curl("ftp://ftp.eu.openbsd.org/pub/OpenBSD/README")
handle.setopt(kore.CURLOPT_TIMEOUT, 5)
data = await handle.run()
print("%s" % data.decode())
A new acme process is created that communicates with the acme servers.
This process does not hold any of your private keys (no account keys,
no domain keys etc).
Whenever the acme process requires a signed payload it will ask the keymgr
process to do the signing with the relevant keys.
This process is also sandboxed with pledge+unveil on OpenBSD and seccomp
syscall filtering on Linux.
The implementation only supports the tls-alpn-01 challenge. This means that
you do not need to open additional ports on your machine.
http-01 and dns-01 are currently not supported (no wildcard support).
A new configuration option "acme_provider" is available and can be set
to the acme server its directory. By default this will point to the
live letsencrypt environment:
https://acme-v02.api.letsencrypt.org/directory
The acme process can be controlled via the following config options:
- acme_root (where the acme process will chroot/chdir into).
- acme_runas (the user the acme process will run as).
If none are set, the values from 'root' and 'runas' are taken.
If you want to turn on acme for domains you do it as follows:
domain kore.io {
acme yes
}
You do not need to specify certkey/certfile anymore, if they are present
still
they will be overwritten by the acme system.
The keymgr will store all certificates and keys under its root
(keymgr_root), the account key is stored as "/account-key.pem" and all
obtained certificates go under "certificates/<domain>/fullchain.pem" while
keys go under "certificates/<domain>/key.pem".
Kore will automatically renew certificates if they will expire in 7 days
or less.
Mostly compliant, ignores \uXXXX in strings for now.
New API functions:
void kore_json_init(struct kore_json *json, const u_int8_t *data, size_t len);
- Prepares JSON data for parsing.
int kore_json_parse(struct kore_json *json)
- Parses the JSON data prepared via kore_json_init. Returns KORE_RESULT_ERROR
if parsing failed or KORE_RESULT_OK if it succeeded.
struct kore_json_item *kore_json_get(struct kore_json *json, const char *path,
int type);
- Try to find the object matching a given search patch and type.
eg, given a JSON structure of:
{
"reasons": {
"strings": [
"first reason",
"second"
]
}
}
one can obtain the second element in the reasons.strings array via:
item = kore_json_get(json, "reasons/strings[0]", KORE_JSON_TYPE_STRING);
Returns NULL if the item was not found or a type mismatch was hit,
otherwise will return the item of that type.
The kore_json_item data structure has a data member that contains the
relevant bits depending on the type:
KORE_JSON_TYPE_ARRAY, KORE_JSON_TYPE_OBJECT:
the data.items member is valid.
KORE_JSON_TYPE_STRING:
the data.string member is valid.
KORE_JSON_TYPE_NUMBER:
the data.number member is valid.
KORE_JSON_TYPE_LITERAL:
the data.literal member is valid.
void kore_json_cleanup(struct kore_json *json);
- Cleanup any resources
const char *kore_json_strerror(struct kore_json *json);
- Return pointer to human readable error string.
Before kore needed to be built with NOTLS=1 to be able to do non TLS
connections. This has been like this for years.
It is time to allow non TLS listeners without having to rebuild Kore.
This commit changes your configuration format and will break existing
applications their config.
Configurations now get listener {} contexts:
listen default {
bind 127.0.0.1 8888
}
The above will create a listener on 127.0.0.1, port 8888 that will serve
TLS (still the default).
If you want to turn off TLS on that listener, specify "tls no" in that
context.
Domains now need to be attached to a listener:
Eg:
domain * {
attach default
}
For the Python API this kills kore.bind(), and kore.bind_unix(). They are
replaced with:
kore.listen("name", ip=None, port=None, path=None, tls=True).
With this commit all Kore processes (minus the parent) are running
under seccomp.
The worker processes get the bare minimum allowed syscalls while each module
like curl, pgsql, etc will add their own filters to allow what they require.
New API functions:
int kore_seccomp_filter(const char *name, void *filter, size_t len);
Adds a filter into the seccomp system (must be called before
seccomp is enabled).
New helpful macro:
define KORE_SYSCALL_ALLOW(name)
Allow the syscall with a given name, should be used in
a sock_filter data structure.
New hooks:
void kore_seccomp_hook(void);
Called before seccomp is enabled, allows developers to add their
own BPF filters into seccomp.
This commit adds the CURL=1 build option. When enabled allows
you to schedule CURL easy handles onto the Kore event loop.
It also adds an easy to use HTTP client API that abstracts away the
settings required from libcurl to make HTTP requests.
Tied together with HTTP request state machines this means you can
write fully asynchronous HTTP client requests in an easy way.
Additionally this exposes that API to the Python code as well
allowing you do to things like:
client = kore.httpclient("https://kore.io")
status, body = await client.get()
Introduces 2 configuration options:
- curl_recv_max
Max incoming bytes for a response.
- curl_timeout
Timeout in seconds before a transfer is cancelled.
This API also allows you to take the CURL easy handle and send emails
with it, run FTP, etc. All asynchronously.
Add KORE_PYTHON_LIB and KORE_PYTHON_INC which can be set
by a caller in case the libraries exist somewhere else.
Add KORE_CRYPTO to be able to override the name of the default
crypto library Kore would link with.
This means you can now do things like:
resp = await koresock.recv(1024)
await koresock.send(resp)
directly from page handlers if they are defined as async.
Adds lots more to the python goo such as fatalx(), bind_unix(),
task_create() and socket_wrap().
A filemap is a way of telling Kore to serve files from a directory
much like a traditional webserver can do.
Kore filemaps only handles files. Kore does not generate directory
indexes or deal with non-regular files.
The way files are sent to a client differs a bit per platform and
build options:
default:
- mmap() backed file transfer due to TLS.
NOTLS=1
- sendfile() under FreeBSD, macOS and Linux.
- mmap() backed file for OpenBSD.
The opened file descriptors/mmap'd regions are cached and reused when
appropriate. If a file is no longer in use it will be closed and evicted
from the cache after 30 seconds.
New API's are available allowing developers to use these facilities via:
void net_send_fileref(struct connection *, struct kore_fileref *);
void http_response_fileref(struct http_request *, struct kore_fileref *);
Kore will attempt to match media types based on file extensions. A few
default types are built-in. Others can be added via the new "http_media_type"
configuration directive.
Mimics how the header files are installed on a system
as PREFIX/include/kore.
This is required for getting kodev to use the headers from the
kore_source option instead of requiring the kore headers to be
installed on the system even when building as a single_binary.
The HTTP layer used to make a copy of each incoming header and its
value for a request. Stop doing that and make HTTP headers zero-copy
all across the board.
This change comes with some api function changes, notably the
http_request_header() function which now takes a const char ** rather
than a char ** out pointer.
This commit also constifies several members of http_request, beware.
Additional rework how the worker processes deal with the accept lock.
Before:
if a worker held the accept lock and it accepted a new connection
it would release the lock for others and back off for 500ms before
attempting to grab the lock again.
This approach worked but under high load this starts becoming obvious.
Now:
- workers not holding the accept lock and not having any connections
will wait less long before returning from kore_platform_event_wait().
- workers not holding the accept lock will no longer blindly wait
an arbitrary amount in kore_platform_event_wait() but will look
at how long until the next lock grab is and base their timeout
on that.
- if a worker its next_lock timeout is up and failed to grab the
lock it will try again in half the time again.
- the worker process holding the lock will when releasing the lock
double check if it still has space for newer connections, if it does
it will keep the lock until it is full. This prevents the lock from
bouncing between several non busy worker processes all the time.
Additional fixes:
- Reduce the number of times we check the timeout list, only do it twice
per second rather then every event tick.
- Fix solo worker count for TLS (we actually hold two processes, not one).
- Make sure we don't accidentally miscalculate the idle time causing new
connections under heavy load to instantly drop.
- Swap from gettimeofday() to clock_gettime() now that MacOS caught up.
Having the create, build, run tools baked into the kore binary
made things harder then they had to be for multiple projects with
each different build flavors.
So move away this functionality into a new "kodev" (name may change)
binary that is installed next to kore.
The new build tools will automatically pick up the correct flavors
the kore binary it points to is installed with. Or for single builds
what flavors where enabled.
The new tool also will honor looking into PREFIX for the kore binary
when doing a `kodev run`.
Additionally add a new command "info" that shows some basic info
about your project and how it will be built. For example it will
show you the flavors of the kore binary installed on the system
or the flavors you configured for a single binary build.
Obligitory, hacking on a plane comment.
The API surface is very limited. Jsonrpc support reads request from HTTP
body and such can't be activated if NOHTTP=1. At the moment there is no
websocket support either (which is a shame). It depends upon the
third-party Yajl library.
Errors can be emitted using jsonrpc_error() and results using
jsonrpc_result(), for the later you'll have to provide a callback which
will write the inner of the result object.
If errors happen during the response write process, no further error
output will be attempted and an HTTP error 500 will be returned.
Read the provided example for getting a better idea of the API.
Producing single binaries can now be done with building with
"kore build". To get started edit your build.conf and add the
following directives:
single_binary = yes
kore_source = /path/to/kore
optionally you can add kore_flavor to instruct how kore should
be built:
kore_flavor = NOTLS=1
When doing this your build.conf must also include the correct
linking options as the linking is now done fully by kore build.
The binary produced will include your configuration and takes
over a few of kore its command line flags (such as -f, -n or -r).
Kore will now isolate RSA private keys to a separate process (keymgr).
Worker processes that require RSA signing for TLS connections will
communicate with this keymgr process in order to do so.
This behaviour cannot be disabled and is always turned on.
- Build with -O2 unless NOOPT is set to 1.
- Hide -g behind DEBUG instead of always building with it.
- Explicitely set the standard used to c99, use pedantic.