kore

An easy to use, scalable and secure web application framework for writing web APIs in C.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

commit 210fb05a35d7968ce546b988ca4ae0b487462215
parent 2e7d6a12a91544e8725575ae705c6824b107e8fa
Author: Joris Vink <joris@coders.se>
Date:   Wed, 13 Aug 2014 23:34:30 +0200

Add a hopefully easy to use and optional fsm for page handlers

In order to use this, define states for your page handler:

struct http_state mystates[] = {
	{ "PAGE_STATE_INIT",	page_init },
	{ "PAGE_STATE_RESULT",	page_result },
};

In your page handler you can then simply call http_state_run() with
your states and http_request. This will cause Kore to start calling
your state callbacks beginning at index 0.

State callbacks have the same prototype as page handlers:

int	func(struct http_request *);

However, unlike page handlers they MUST return one of the following:

- HTTP_STATE_OK:	All good, just continue the fsm.
- HTTP_STATE_ERROR:	Abort fsm and return KORE_RESULT_OK to Kore
			(This will cancel the http request).
- HTTP_STATE_RETRY:	Return KORE_RESULT_RETRY to Kore.
			(Kore will retry your page handler next event loop).
- HTTP_STATE_COMPLETE:	The fsm completed, break out cleanly.

Note that using this is completely optional and you can still
use the traditional way of writing page handlers.

The fsm is designed to get rid of the clutter that exists today
in Kore when dealing with non blocking tasks or pgsql calls.

Diffstat:
includes/http.h | 13+++++++++++++
src/http.c | 38++++++++++++++++++++++++++++++++++++++
2 files changed, 51 insertions(+), 0 deletions(-)

diff --git a/includes/http.h b/includes/http.h @@ -37,6 +37,11 @@ #define HTTP_ARG_TYPE_INT64 7 #define HTTP_ARG_TYPE_UINT64 8 +#define HTTP_STATE_ERROR 0 +#define HTTP_STATE_OK 1 +#define HTTP_STATE_COMPLETE 2 +#define HTTP_STATE_RETRY 3 + struct http_header { char *header; char *value; @@ -159,6 +164,7 @@ struct kore_task; struct http_request { u_int8_t method; u_int8_t flags; + u_int8_t fsm_state; int status; u_int64_t start; u_int64_t end; @@ -185,6 +191,11 @@ struct http_request { TAILQ_ENTRY(http_request) olist; }; +struct http_state { + const char *name; + int (*cb)(struct http_request *); +}; + extern int http_request_count; extern u_int16_t http_header_max; extern u_int64_t http_postbody_max; @@ -210,6 +221,8 @@ void http_response_header(struct http_request *, int http_request_new(struct connection *, struct spdy_stream *, const char *, const char *, const char *, const char *, struct http_request **); +int http_state_run(struct http_state *, u_int8_t, + struct http_request *); int http_argument_urldecode(char *); int http_header_recv(struct netbuf *); diff --git a/src/http.c b/src/http.c @@ -122,6 +122,7 @@ http_request_new(struct connection *c, struct spdy_stream *s, const char *host, req->hdlr = NULL; req->agent = NULL; req->flags = flags; + req->fsm_state = 0; req->post_data = NULL; req->hdlr_extra = NULL; req->query_string = NULL; @@ -949,6 +950,43 @@ http_post_data_bytes(struct http_request *req, u_int32_t *len) return (data); } +int +http_state_run(struct http_state *states, u_int8_t elm, + struct http_request *req) +{ + int r, done; + + done = 0; + + while (!done) { + if (req->fsm_state >= elm) { + fatal("http_state_run: fsm_state > elm (%d/%d)", + req->fsm_state, elm); + } + + kore_debug("http_state_run: running %s", + states[req->fsm_state].name); + + r = states[req->fsm_state].cb(req); + switch (r) { + case HTTP_STATE_ERROR: + return (KORE_RESULT_OK); + case HTTP_STATE_RETRY: + return (KORE_RESULT_RETRY); + case HTTP_STATE_OK: + break; + case HTTP_STATE_COMPLETE: + done = 1; + break; + default: + fatal("http_state_run: unknown return value %d", r); + } + } + + kore_debug("http_state_run(%p): done", req); + return (KORE_RESULT_OK); +} + static void http_argument_add(struct http_request *req, const char *name, void *value, u_int32_t len, int type)