Commit Graph

199 Commits

Author SHA1 Message Date
Joris Vink 95506204e8 Add kore.task_kill() to the python api.
Allows killing of coroutines, given their task id.

The kore.task_create() method now returns the task id for a newly
created task to the caller.

While here, change the coroutine task id to a uint32 from uint64.
There is no need for it to be 64bit. (famous last words)
2019-09-17 20:04:35 +02:00
Joris Vink c1653a5254 hide kore.coroname() behind PYTHON_CORO_TRACE. 2019-09-16 20:33:14 +02:00
Joris Vink 019006620d allow coroutines to set friendly names. 2019-09-16 20:31:25 +02:00
Joris Vink 9bcccb9483 Add coroutine debugging.
If built with PYTHON_CORO_DEBUG in CFLAGS Kore will spew out coroutine
traces while running. These traces include the filename, function and line
number where the coroutines are waking up, running and suspended.
2019-09-16 20:11:42 +02:00
Joris Vink f2472ba485 allow python modules to set progname. 2019-09-04 20:37:33 +02:00
Joris Vink 8e858983bf python pgsql changes.
- decouple pgsql from the HTTP request allowing it to be used in other
  contexts as well (such as a task, etc).

- change names to dbsetup() and dbquery().

eg:

result = kore.dbquery("db", "select foo from bar")
2019-09-04 19:57:28 +02:00
Joris Vink 5055f3c872 add kore.worker() to the python api.
returns the current worker number or None if on parent.
2019-06-16 19:57:48 +02:00
Joris Vink 4a64b4f07b Improve curl timeout handling.
In case libcurl instructs us to call the timeout function as soon
as possible (timeout == 0 in curl_timeout), don't try to be clever
with a timeout value of 10ms.

Instead call the timeout function once we get back in the worker
event loop. This makes things a lot snappier as we don't depend
on epoll/kqueue waiting for io for 10ms (which actually isn't 10ms...).
2019-06-13 12:59:17 +02:00
Joris Vink 3114f8d8d0 Improve python experience.
- If Kore is built with PYTHON=1 you can now specify the module that
  should be loaded on the command-line.

     eg: $ kore -frn myapp

- Add skeleton generation for python applications to kodev.

     eg: $ kodev create -p myapp

This should make it a whole lot easier to get started with kore python.
2019-06-12 23:35:43 +02:00
Joris Vink 6c18856a3e get rid of mtime in modules.
kore should always reload things when it was told to reload things.
there are use cases were a module reload is because the code itself changed.
2019-06-09 23:24:53 +02:00
Joris Vink 3cc7d6e238 Allow kore.prerequests to be async. 2019-06-07 21:06:54 +02:00
Joris Vink 9cc58d45c1 Python HTTP improvements.
1) Add @kore.prerequest python decorator.

Using this decorator on a function will cause that function
to always be executed *before* any page handler is run.

eg:

@kore.prerequest
def _check(req):
    if req.method == kore.HTTP_METHOD_POST:
        req.populate_post()

2) Allow attributes to be set on the pyhttp object.
2019-06-05 23:45:45 +02:00
Joris Vink 93b1d621d7 Remove memleak from Python httpclient.
We grab a reference to the pyhttp_client for the client_op data structure
but never removed it. This caused the pyhttp_client object to never
be released when out of scope.
2019-06-05 10:27:20 +02:00
Joris Vink a4d18ca276 Add HTTP runlocks.
A way to serialize access to HTTP page handlers in case you are
using some asynchronous api such as pgsql or libcurl stuff.
2019-06-02 16:29:54 +02:00
Joris Vink 1686ec22e6 Some C pgsql api improvements. 2019-06-01 23:14:50 +02:00
Joris Vink a8aff8b737 Improve curl error string handling.
Introduce kore_curl_strerror(), use this in kore_curl_logerror()
instead of assuming our errbuf has been populated.

Also use it in the python httpclient when throwing an exception rather
then looking at the errbuf member which may or may not be empty.
2019-05-30 14:25:04 +02:00
Joris Vink 3299f60df4 tiny curl fixes. 2019-05-05 21:16:42 +02:00
Joris Vink fe84997ce9 add option to use unix paths via kore.httpclient 2019-05-03 15:31:16 +02:00
Joris Vink 3c9a141cd0 allow an iterator to be passed to req.response().
if an iterator is passed kore will send the response with
transfer-encoding: chunked and call the iterator for every
chunk that was sent.

The iterator must return a utf-8 string.

Works wonderful with TemplateStream from jinja2.
2019-05-03 13:42:34 +02:00
Joris Vink d0a6958747 Let http_state_create() take an "onfree" callback.
This function is called when an HTTP request is being free'd,
allowing you to perform any sort of state cleanup attached
to the HTTP request.
2019-04-28 21:48:16 +02:00
Joris Vink d0d0bdeb4f Improve pgsql support.
- Add kore_pgsql_query_param_fields() which allows you to pass in the
  arrays for values, lengths and formats yourself.

- Add kore_pgsql_column_binary() which will return 1 if the given column
  index contains a binary result or 0 if it contains a text result.

- Change the query call in req.pgsql() for Python to always use the
  parameterized queries.

This adds the 'params' and 'binary' keywords to the req.pgsql method.

Eg:
	result = await req.pgsql("db", "INSERT INTO foo (field) VALUES($1"),
	    params=["this is my value"])
2019-04-25 23:13:13 +02:00
Joris Vink 994f428a8d add cabundle keyword to kore.httpclient() 2019-04-24 21:09:24 +02:00
Joris Vink a6af458cd2 add tlsverify keyword to kore.httpclient(). 2019-04-24 18:28:23 +02:00
Joris Vink 2c88bc6120 Add asynchronous libcurl support.
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.
2019-04-24 00:15:17 +02:00
Joris Vink aa49e181b6 Add http_[header|body]_timeout.
If the HTTP request headers or the HTTP body have not arrived before
these timeouts expire, Kore will send a 408 back to the client.
2019-04-11 20:51:49 +02:00
Joris Vink d2aa64df5c add kore_proctitle().
manipulates the argv+environ pointers to get a sensible process title
under linux / darwin.
2019-03-29 16:24:14 +01:00
Joris Vink 4ca7f29649 Add a concurrency parameter to kore.gather() 2019-03-25 10:13:52 +01:00
Joris Vink 4238431b9e Add worker_death_policy setting.
By default kore will restart worker processes if they terminate
unexpected. However in certain scenarios you may want to bring down
an entire kore instance if a worker process fails.

By setting worker_death_policy to "terminate" the Kore server will
completely stop if a worker exits unexpected.
2019-03-22 09:49:50 +01:00
Joris Vink 370041656e Get rid of WORKER_LOCK_TIMEOUT.
Instead let the workers send a message on the msg channel to each
other when they have given up the accept lock and it is now available
to be grabbed.
2019-03-21 14:03:11 +01:00
Joris Vink 8b0279879a rework timers so they fire more predictably.
this change also stops python coroutines from waking up very
late after their timeout has expired.

in filerefs, don't prime the timer until we actually have something
to expire, and kill the timer when the last ref drops.
2019-03-21 10:17:08 +01:00
Joris Vink 9caa45a050 Allow python validator methods to be async. 2019-03-18 09:34:31 +01:00
Joris Vink 31b6365da3 include sys/types.h explictly. 2019-03-14 19:20:46 +01:00
Joris Vink 3b4574d791 Rework pysocket async/await.
Attach the events directly to the pysocket data structure instead of
one event per pysocket_op.

Makes the code easier, gives us a good performance boost and reduces
the number of system calls required when doing an await on a socket.
2019-03-13 11:07:15 +01:00
Joris Vink 31a9a70d5a cleanup. 2019-03-01 20:56:03 +01:00
Erik Karlsson 01c1a8f8f8 support AF_UNIX in recvfrom()/sendto() python sockets 2019-03-01 20:13:28 +01:00
Joris Vink f4cd70956b Add an optional timeout to socketop.recv(). 2019-02-25 10:35:00 +01:00
Joris Vink bf1e8e5ffb bump copyright to 2019 2019-02-22 16:57:28 +01:00
Joris Vink d6b05bcff7 always force reload cert so we get a new x509 store.
Otherwise older OpenSSL or current LibreSSL will fail to add the new
CRL as they still match on subject name rather then hash of the CRL data.
2019-01-14 20:57:40 +01:00
Joris Vink 73cdbd1a01 Let CRLs be reloadable via keymgr.
With these changes CRLs can be reloaded like certificates
by sending a SIGUSR1 to the parent process.

Track mtime on both certificate files and CRL files as well
and only submit them to the workers if this has changed.
2019-01-14 11:41:50 +01:00
Joris Vink c070e77ea5 include signal.h from kore.h 2019-01-11 11:32:33 +01:00
Joris Vink b07cc0237c Support recvfrom()/sendto() on kore python sockets. 2019-01-08 17:49:00 +01:00
Joris Vink 7aa17df4a1 make ACCESSLOG_* unsigned 2018-12-22 10:52:57 +01:00
Joris Vink 4d184e00de correct define number 2018-12-22 10:22:59 +01:00
Joris Vink 9aa0e95643 Rework accesslog handling.
Move away from the parent constantly hitting the disk for every
accesslog the workers are sending.

The workers will now write their own accesslogs to shared
memory before the parent will pick those up. The parent
will flush them to disk once every second or if they grow
larger then 1MB.

This removes the heavy penalty for having access logs
turned on when you are dealing with a large volume
of requests.
2018-12-22 09:25:00 +01:00
Joris Vink 272d659f1c we use certain things from sys/param.h 2018-11-29 10:31:14 +01:00
Joris Vink d9f543ef5b Allow user-supplied tracer callback. 2018-11-29 09:51:24 +01:00
Joris Vink c431c2bf72 Add support to obtain peer certificate from Python
This will return the DER encoded bytes representing the peer certificate.
2018-11-28 11:28:07 +01:00
Joris Vink baafa4897e Add -q flag.
If specified Kore will run quietly and only log important messages.
2018-11-15 16:01:37 +01:00
Joris Vink 966eaf8f7a Add a kore_python_preinit() hook.
This is called before the python initialization is completed
and allows developers to inject their own built-in methods.
2018-11-12 09:01:05 +01:00
Joris Vink 2dd66586ff several python improvements.
- add kore.time() as equivalent for kore_time_ms().
- call waitpid() until no more children are available for reaping otherwise
  we risk missing a process if several die at the same time and only one
  SIGCHLD is delivered to us.
- drain a RECV socket operation if eof is set but no exception was given.
2018-10-30 20:28:27 +01:00
Joris Vink 71c145932c grow kore_pools at a slower rate.
Before we just doubled in size the second we exhausted a pool instead
of doing a more controlled expansion.

Now we will expand at 25% of the initial elm count whenever we need to.

Will help with memory pressure in certain scenarios.
2018-10-30 10:36:18 +01:00
Joris Vink 1c30da855c Add kore.gather() to the python api.
Allows one to run coroutines concurrently and gather all their
results in a single returned list.

If any of the coroutines throw an exception the exception is
returned as the value of that coroutine in the returned list.
2018-10-29 21:16:08 +01:00
Joris Vink 339df66fd5 Add support for TLS 1.3 via OpenSSL 1.1.1.
This commit removes TLS 1.0 support no matter what OpenSSL
you are linking against.

Changes the value of tls_version from 1.2 to both. Meaning if
you link with OpenSSL 1.1.1 you will get 1.2 + 1.3.
2018-10-29 20:38:58 +01:00
Joris Vink dda2e1fb2c Some things still talk http/1.0. 2018-10-26 21:24:51 +02:00
Joris Vink e2651889e0 Add asynchronous subprocess support.
This adds kore.proc to the python runtime allowing async processing
handling:

The kore.proc method takes the command to run and an optional timeout
parameter in milliseconds. If the process did not exit normally after
that amount of time a TimeoutError exception is raised.

For instance:

async def run(cmd):
	proc = kore.proc(cmd, 1000)

	try:
		await proc.send("hello")
		proc.close_stdin()
	except TimeoutError:
		proc.kill()

	retcode = await proc.reap()

	return retcode
2018-10-26 19:19:47 +02:00
Joris Vink 892814e353 Add kore_[parent|worker]_teardown().
If exists these functions are called when the worker is exiting
and when right before the parent exists.

Allows for cleanup code for applications if need to do cleanup on exit.
2018-10-23 21:46:34 +02:00
Joris Vink 8ea32983ae Add kore.suspend(delay) to python.
Will suspend the coroutine for a number of milliseconds.

Example:

async def page(req):
	await kore.suspend(1000)
	req.response(200, b'')
2018-10-23 21:32:08 +02:00
Joris Vink 47776a9fbb Hook kore timers into python. 2018-10-23 20:44:43 +02:00
Joris Vink c41c1db303 Add kore_shutdown().
Allows workers to cleanly initiate a shutdown of the
entire server process.
2018-10-23 19:49:42 +02:00
Joris Vink b70d1ee80f Add a locking mechanism in pykore.
Support the async with syntax:

	lock = kore.lock()

	async with lock:
		# your block

Fix some small issues with other parts of the python system.
2018-10-22 20:09:23 +02:00
Joris Vink fad5c6ea6f Give pyqueues "popnow". 2018-10-22 08:28:03 +02:00
Joris Vink c8795b7d7f pyqueue improvements.
- cleanup queue if it gets deallocated.
- make sure waitables on a queue get removed if their pyqueue_op dies.
2018-10-21 21:58:34 +02:00
Joris Vink 0cda9ecfb0 Add an asynchronous queue mechanism.
This allows coroutines to submit messages to and pop
messages from a queue in an asynchronous way.
2018-10-18 22:15:21 +02:00
Joris Vink b5958f7d7d Add kore_parent_daemonized().
This is called for single binaries after the parent
process has called daemon().

Also fix kore_parent_configure() for !single binaries.
2018-10-18 17:18:41 +02:00
Joris Vink 29202d7330 Make kore_python_log_error() public.
While here also make kore_module_load() return the
kore_module data structure pointer it just added
to the modules list.
2018-10-16 13:16:36 +02:00
Joris Vink 20a0103f1e Add async/await support for socket i/o in python.
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().
2018-10-15 20:18:54 +02:00
Joris Vink c463ecb3cb Changes to the event loop inside of Kore.
Now anyone can schedule events and get a callback to work as long
as the user data structure that is added for the event begins
with a kore_event data structure.

All event state is now kept in that kore_event structure and renamed
CONN_[READ|WRITE]_POSSIBLE to KORE_EVENT_[READ|WRITE].
2018-10-09 19:34:40 +02:00
Joris Vink 9427ed8a2e rename unix to sun 2018-10-07 21:03:12 +02:00
Joris Vink 442bdef79b allow kore to bind to unix sockets via bind_unix. 2018-10-07 20:49:16 +02:00
Joris Vink b0074ba45e Add fatalx().
If a worker process dies it automatically gets respawned by the
parent process, but sometimes you want the entire server to go down
if a worker encounters an error. This is what fatalx() does.

Calling fatalx() from a worker process will initiate a full shutdown
of the kore server you are running under.
2018-08-13 09:53:49 +02:00
Joris Vink a927acb7ee Add pledge support under OpenBSD.
All worker processes will now call pledge(2) after dropping
privileges (even if -rn was specified).

By default Kore will use the following promises:
	"stdio rpath inet error"

If your application requires more privileges, you can add more pledges
by setting them in your configuration using the 'pledge' directive:
	pledge dns wpath
2018-07-31 06:51:34 +02:00
Joris Vink f126ba5a86 sprinkle more const around 2018-07-25 09:54:34 +02:00
Joris Vink cf1f624367 let filerefs to operate on ms precision for mtime. 2018-07-24 19:56:36 +02:00
Joris Vink a6e662a805 Add KORE_HTTP_STATE() helper macro.
defines as KORE_HTTP_STATE(f) (#f, f) so we can get a literal representing
the name of the state function which makes debugging a little easier.
2018-07-23 06:14:17 +02:00
Joris Vink 7f820c96e8 Make kore_auth_* public. 2018-07-19 10:28:38 +02:00
Joris Vink 2e321f14de Add KORE_PGSQL_STATE_NOTIFY.
Issue a LISTEN channel on a kore_pgsql, bind a callback to it and you
will get called with pgsql->state being KORE_PGSQL_STATE_NOTIFY.
2018-07-18 11:38:17 +02:00
Joris Vink ac5a89fbeb pull in openssl/sha.h for body digest 2018-07-17 15:07:26 +02:00
Joris Vink 616af063e3 Calculate an md over the incoming HTTP body.
This is calculated while the HTTP body is incoming over the wire, once
the body is fully received the digest will be available for the page
handlers to obtain.

You can obtain a hex string for this md via http_body_digest() or
dereferences the http_request and look at http_body_digest manually
for the bytes.
2018-07-17 14:53:55 +02:00
Joris Vink 40a81a17ba remove kore_module_handle for NOHTTP=1 builds. 2018-07-17 14:28:43 +02:00
Joris Vink 0726a26c0c Allow restriction of methods for paths.
Now Kore will automatically send a 400 bad request in case the
method was not allowed on the path.
2018-07-17 14:23:57 +02:00
Joris Vink 02e7359970 Add kore_worker_make_busy().
Calling this from your page handler will cause your current worker
to give up the acceptlock (if it holds it).

This is particularly useful if you are about to run code that may block
a bit longer then you are comfortable with. Calling this will cause
the acceptlock to shuffle to another free worker which in turn makes
sure your application can keep accepting requests.
2018-07-11 18:00:16 +02:00
Joris Vink cffb7ec379 Allow on-the-fly reloading of certificates/keys.
This commit introduces the ability for the keymgr process
to reload the certificates/keys for domains when receiving
a SIGUSR1 signal.

The keymgr receives 2 new configuration options:
	- keymgr_root_path
		The root path where the keymgr will live.
		If -n is not specified when the application starts the
		keymgr process will chroot into here.

	- keymgr_runas_user
		The user the keymgr will drop privileges towards if
		-r was not specified.

All certfile and certkey configuration options are now relative to the
keymgr_root_path configuration setting.

The keymgr process will now also load the certificate for the domain
(rather then the workers) and submit these to the worker processes so
they can be reloaded when required.

Worker processes will refuse connections until the TLS configuration
for a given domain is completed (aka: the workers receive the certificate
for that domain).

Other changes:
	- client_certificates renamed to client_verify.
	- the chroot configuration option is now called root.
	- kore is a little more verbose if privsep options are missing.
	- filemaps are now relative to the root configuration option.
2018-07-11 09:44:29 +02:00
Joris Vink bf6c0e150f Let kore_worker_privdrop() take user and chroot.
This will make it easier when the keymgr gets its own user/chroot settings.
2018-07-11 06:53:51 +02:00
Joris Vink 5eb2160269 resolve filemap paths after workers chrooted.
otherwise the paths inside chrooted workers are incorrect.
2018-07-08 17:51:35 +02:00
Joris Vink 04077c66b6 Add filemap_ext configuration option.
Allows you to specify the default extensions used for a file served
via a filemap, eg:
	filemap_ext	.html

Gives us ability to provide clean urls.
2018-07-03 19:58:43 +02:00
Joris Vink 4a8d8ab7f8 log referer in accesslog if present. 2018-06-29 22:37:48 +02:00
Joris Vink 6dca7d51e6 update prototype for kore_date_to_time() 2018-06-29 09:56:38 +02:00
Joris Vink 3e5939a8e3 make sure fileref is dropped if softremoved 2018-06-29 05:03:50 +02:00
Joris Vink 202234cf97 filemap and fileref improvements.
- make sure we can serve updated files even if we have an old
  fileref around.

- add filemap_index as a configuration option: allows one to specify
  what file to serve if a directory was requested (eg: index.html)
2018-06-28 23:00:42 +02:00
Joris Vink 80f5425698 Add filemaps.
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.
2018-06-28 13:27:44 +02:00
Joris Vink 8aaf7aaf79 Alter where the version number comes from.
Now if we are a git repo we fetch the branch name and
commitid to build the version string. If there is no
git repo we'll look at the RELEASE file.
2018-06-22 14:24:42 +02:00
Joris Vink e475bd0c92 Add configurable x509 chain validation depth.
You can now per domain configure the depth for x509 chain validation:
	client_verify_depth	1

By default this is 1.

While here change around some log messages and properly set
the callback for x509 verification rather then via hoops and loops.
2018-06-09 12:50:50 +02:00
Joris Vink 9e12b2c6dd Use sigaction() for signals.
Don't duplicate signal setup code between parent and worker processes.
2018-05-25 20:49:02 +02:00
Joris Vink 439a3b36f0 Add kore_strtodouble().
Use it for http_argument_get_float() and http_argument_get_double().
2018-05-04 15:55:35 +02:00
Sebastiaan a3cab0d97b Websocket memory leak fix when using kore_websocket_send() to send data. (#238) 2018-04-13 07:40:37 +02:00
Joris Vink 65666942e6 we're still in dev, not rc. 2018-04-09 14:23:55 +02:00
Joris Vink a33ce78a19 it's time. 2018-04-09 14:14:00 +02:00
Joris Vink 9c337ded1e Change kore_parent_configure() for single binaries.
This function now takes any remaining arguments passed on the command line
after kore parsed its own.

For C the new prototype looks like this:

void kore_parent_configure(int argc, char **argv);

For python code, kore will pass each argument to the function so you
can do things like:

def kore_parent_configure(arg1, arg2):
2018-04-09 12:51:20 +02:00
Joris Vink e6833a4892 Move header files to include/kore.
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.
2018-03-30 13:45:29 +02:00