From 8a3241d5c46e8b8fac382f606147285e314f1f6b Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Mon, 2 Mar 2015 08:49:21 +0100 Subject: Initial commit Not even the demo is able to compile yet. I'm just tracking my progress. --- liberty | 1 + 1 file changed, 1 insertion(+) create mode 160000 liberty (limited to 'liberty') diff --git a/liberty b/liberty new file mode 160000 index 0000000..0876458 --- /dev/null +++ b/liberty @@ -0,0 +1 @@ +Subproject commit 087645848baec5e59e4296817850bd5dd240cbb2 -- cgit v1.2.3-54-g00ecf From db6dff421667e4e7ab5ea24440f28fb55baeee7b Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 29 Mar 2015 03:14:20 +0200 Subject: Move a lot of stuff to liberty --- demo-json-rpc-server.c | 1544 +----------------------------------------------- liberty | 2 +- 2 files changed, 25 insertions(+), 1521 deletions(-) (limited to 'liberty') diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index 8aa070b..2196217 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -25,6 +25,10 @@ #define print_debug_data ((void *) LOG_DEBUG) #define LIBERTY_WANT_SSL +#define LIBERTY_WANT_PROTO_HTTP +#define LIBERTY_WANT_PROTO_WS +#define LIBERTY_WANT_PROTO_SCGI +#define LIBERTY_WANT_PROTO_FASTCGI #include "config.h" #include "liberty/liberty.c" @@ -42,640 +46,7 @@ // --- Extensions to liberty --------------------------------------------------- -// These should be incorporated into the library ASAP - -#define UNPACKER_INT_BEGIN \ - if (self->len - self->offset < sizeof *value) \ - return false; \ - uint8_t *x = (uint8_t *) self->data + self->offset; \ - self->offset += sizeof *value; - -static bool -msg_unpacker_u16 (struct msg_unpacker *self, uint16_t *value) -{ - UNPACKER_INT_BEGIN - *value - = (uint16_t) x[0] << 24 | (uint16_t) x[1] << 16; - return true; -} - -static bool -msg_unpacker_u32 (struct msg_unpacker *self, uint32_t *value) -{ - UNPACKER_INT_BEGIN - *value - = (uint32_t) x[0] << 24 | (uint32_t) x[1] << 16 - | (uint32_t) x[2] << 8 | (uint32_t) x[3]; - return true; -} - -#undef UNPACKER_INT_BEGIN - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// "msg_writer" should be rewritten on top of this - -static void -str_pack_u8 (struct str *self, uint8_t x) -{ - str_append_data (self, &x, 1); -} - -static void -str_pack_u16 (struct str *self, uint64_t x) -{ - uint8_t tmp[2] = { x >> 8, x }; - str_append_data (self, tmp, sizeof tmp); -} - -static void -str_pack_u32 (struct str *self, uint32_t x) -{ - uint32_t u = x; - uint8_t tmp[4] = { u >> 24, u >> 16, u >> 8, u }; - str_append_data (self, tmp, sizeof tmp); -} - -static void -str_pack_i32 (struct str *self, int32_t x) -{ - str_pack_u32 (self, (uint32_t) x); -} - -static void -str_pack_u64 (struct str *self, uint64_t x) -{ - uint8_t tmp[8] = - { x >> 56, x >> 48, x >> 40, x >> 32, x >> 24, x >> 16, x >> 8, x }; - str_append_data (self, tmp, sizeof tmp); -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static int -tolower_ascii (int c) -{ - return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c; -} - -static size_t -tolower_ascii_strxfrm (char *dest, const char *src, size_t n) -{ - size_t len = strlen (src); - while (n-- && (*dest++ = tolower_ascii (*src++))) - ; - return len; -} - -static int -strcasecmp_ascii (const char *a, const char *b) -{ - while (*a && tolower_ascii (*a) == tolower_ascii (*b)) - { - a++; - b++; - } - return *(const unsigned char *) a - *(const unsigned char *) b; -} - -static bool -isspace_ascii (int c) -{ - return c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v'; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/// Return a pointer to the next UTF-8 character, or NULL on error -// TODO: decode the sequence while we're at it -static const char * -utf8_next (const char *s, size_t len) -{ - // End of string, we go no further - if (!len) - return NULL; - - // In the middle of a character -> error - const uint8_t *p = (const unsigned char *) s; - if ((*p & 0xC0) == 0x80) - return NULL; - - // Find out how long the sequence is - unsigned mask = 0xC0; - unsigned tail_len = 0; - while ((*p & mask) == mask) - { - // Invalid start of sequence - if (mask == 0xFE) - return NULL; - - mask |= mask >> 1; - tail_len++; - } - - p++; - - // Check the rest of the sequence - if (tail_len > --len) - return NULL; - - while (tail_len--) - if ((*p++ & 0xC0) != 0x80) - return NULL; - - return (const char *) p; -} - -/// Very rough UTF-8 validation, just makes sure codepoints can be iterated -// TODO: also validate the codepoints -static bool -utf8_validate (const char *s, size_t len) -{ - const char *next; - while (len) - { - if (!(next = utf8_next (s, len))) - return false; - - len -= next - s; - s = next; - } - return true; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static uint8_t g_base64_table[256] = -{ - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 0, 64, 64, - 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, - 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, - - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, -}; - -static inline bool -base64_decode_group (const char **s, bool ignore_ws, struct str *output) -{ - uint8_t input[4]; - size_t loaded = 0; - for (; loaded < 4; (*s)++) - { - if (!**s) - return loaded == 0; - if (!ignore_ws || !isspace_ascii (**s)) - input[loaded++] = **s; - } - - size_t len = 3; - if (input[0] == '=' || input[1] == '=') - return false; - if (input[2] == '=' && input[3] != '=') - return false; - if (input[2] == '=') - len--; - if (input[3] == '=') - len--; - - uint8_t a = g_base64_table[input[0]]; - uint8_t b = g_base64_table[input[1]]; - uint8_t c = g_base64_table[input[2]]; - uint8_t d = g_base64_table[input[3]]; - - if (((a | b) | (c | d)) & 0x40) - return false; - - uint32_t block = a << 18 | b << 12 | c << 6 | d; - switch (len) - { - case 1: - str_append_c (output, block >> 16); - break; - case 2: - str_append_c (output, block >> 16); - str_append_c (output, block >> 8); - break; - case 3: - str_append_c (output, block >> 16); - str_append_c (output, block >> 8); - str_append_c (output, block); - } - return true; -} - -static bool -base64_decode (const char *s, bool ignore_ws, struct str *output) -{ - while (*s) - if (!base64_decode_group (&s, ignore_ws, output)) - return false; - return true; -} - -static void -base64_encode (const void *data, size_t len, struct str *output) -{ - const char *alphabet = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - const uint8_t *p = data; - size_t n_groups = len / 3; - size_t tail = len - n_groups * 3; - uint32_t group; - - for (; n_groups--; p += 3) - { - group = p[0] << 16 | p[1] << 8 | p[2]; - str_append_c (output, alphabet[(group >> 18) & 63]); - str_append_c (output, alphabet[(group >> 12) & 63]); - str_append_c (output, alphabet[(group >> 6) & 63]); - str_append_c (output, alphabet[ group & 63]); - } - - switch (tail) - { - case 2: - group = p[0] << 16 | p[1] << 8; - str_append_c (output, alphabet[(group >> 18) & 63]); - str_append_c (output, alphabet[(group >> 12) & 63]); - str_append_c (output, alphabet[(group >> 6) & 63]); - str_append_c (output, '='); - break; - case 1: - group = p[0] << 16; - str_append_c (output, alphabet[(group >> 18) & 63]); - str_append_c (output, alphabet[(group >> 12) & 63]); - str_append_c (output, '='); - str_append_c (output, '='); - default: - break; - } -} - -// --- HTTP parsing ------------------------------------------------------------ - -// Basic tokenizer for HTTP header field values, to be used in various parsers. -// The input should already be unwrapped. - -// Recommended literature: -// http://tools.ietf.org/html/rfc7230#section-3.2.6 -// http://tools.ietf.org/html/rfc7230#appendix-B -// http://tools.ietf.org/html/rfc5234#appendix-B.1 - -#define HTTP_TOKENIZER_CLASS(name, definition) \ - static inline bool \ - http_tokenizer_is_ ## name (int c) \ - { \ - return (definition); \ - } - -HTTP_TOKENIZER_CLASS (vchar, c >= 0x21 && c <= 0x7E) -HTTP_TOKENIZER_CLASS (delimiter, !!strchr ("\"(),/:;<=>?@[\\]{}", c)) -HTTP_TOKENIZER_CLASS (whitespace, c == '\t' || c == ' ') -HTTP_TOKENIZER_CLASS (obs_text, c >= 0x80 && c <= 0xFF) - -HTTP_TOKENIZER_CLASS (tchar, - http_tokenizer_is_vchar (c) && !http_tokenizer_is_delimiter (c)) - -HTTP_TOKENIZER_CLASS (qdtext, - c == '\t' || c == ' ' || c == '!' - || (c >= 0x23 && c <= 0x5B) - || (c >= 0x5D && c <= 0x7E) - || http_tokenizer_is_obs_text (c)) - -HTTP_TOKENIZER_CLASS (quoted_pair, - c == '\t' || c == ' ' - || http_tokenizer_is_vchar (c) - || http_tokenizer_is_obs_text (c)) - -#undef HTTP_TOKENIZER_CLASS - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -enum http_tokenizer_token -{ - HTTP_T_EOF, ///< Input error - HTTP_T_ERROR, ///< End of input - - HTTP_T_TOKEN, ///< "token" - HTTP_T_QUOTED_STRING, ///< "quoted-string" - HTTP_T_DELIMITER, ///< "delimiters" - HTTP_T_WHITESPACE ///< RWS/OWS/BWS -}; - -struct http_tokenizer -{ - const unsigned char *input; ///< The input string - size_t input_len; ///< Length of the input - size_t offset; ///< Position in the input - - char delimiter; ///< The delimiter character - struct str string; ///< "token" / "quoted-string" content -}; - -static void -http_tokenizer_init (struct http_tokenizer *self, const char *input, size_t len) -{ - memset (self, 0, sizeof *self); - self->input = (const unsigned char *) input; - self->input_len = len; - - str_init (&self->string); -} - -static void -http_tokenizer_free (struct http_tokenizer *self) -{ - str_free (&self->string); -} - -static enum http_tokenizer_token -http_tokenizer_quoted_string (struct http_tokenizer *self) -{ - bool quoted_pair = false; - while (self->offset < self->input_len) - { - int c = self->input[self->offset++]; - if (quoted_pair) - { - if (!http_tokenizer_is_quoted_pair (c)) - return HTTP_T_ERROR; - - str_append_c (&self->string, c); - quoted_pair = false; - } - else if (c == '\\') - quoted_pair = true; - else if (c == '"') - return HTTP_T_QUOTED_STRING; - else if (http_tokenizer_is_qdtext (c)) - str_append_c (&self->string, c); - else - return HTTP_T_ERROR; - } - - // Premature end of input - return HTTP_T_ERROR; -} - -static enum http_tokenizer_token -http_tokenizer_next (struct http_tokenizer *self, bool skip_ows) -{ - str_reset (&self->string); - if (self->offset >= self->input_len) - return HTTP_T_EOF; - - int c = self->input[self->offset++]; - - if (skip_ows) - while (http_tokenizer_is_whitespace (c)) - { - if (self->offset >= self->input_len) - return HTTP_T_EOF; - c = self->input[self->offset++]; - } - - if (c == '"') - return http_tokenizer_quoted_string (self); - - if (http_tokenizer_is_delimiter (c)) - { - self->delimiter = c; - return HTTP_T_DELIMITER; - } - - // Simple variable-length tokens - enum http_tokenizer_token result; - bool (*eater) (int c) = NULL; - if (http_tokenizer_is_whitespace (c)) - { - eater = http_tokenizer_is_whitespace; - result = HTTP_T_WHITESPACE; - } - else if (http_tokenizer_is_tchar (c)) - { - eater = http_tokenizer_is_tchar; - result = HTTP_T_TOKEN; - } - else - return HTTP_T_ERROR; - - str_append_c (&self->string, c); - while (self->offset < self->input_len) - { - if (!eater (c = self->input[self->offset])) - break; - - str_append_c (&self->string, c); - self->offset++; - } - return result; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -static bool -http_parse_media_type_parameter - (struct http_tokenizer *t, struct str_map *parameters) -{ - bool result = false; - char *attribute = NULL; - - if (http_tokenizer_next (t, true) != HTTP_T_TOKEN) - goto end; - attribute = xstrdup (t->string.str); - - if (http_tokenizer_next (t, false) != HTTP_T_DELIMITER - || t->delimiter != '=') - goto end; - - switch (http_tokenizer_next (t, false)) - { - case HTTP_T_TOKEN: - case HTTP_T_QUOTED_STRING: - str_map_set (parameters, attribute, xstrdup (t->string.str)); - result = true; - default: - break; - } - -end: - free (attribute); - return result; -} - -/// Parser for "Content-Type". @a type and @a subtype may be non-NULL -/// even if the function fails. @a parameters should be case-insensitive. -static bool -http_parse_media_type (const char *media_type, - char **type, char **subtype, struct str_map *parameters) -{ - bool result = false; - struct http_tokenizer t; - http_tokenizer_init (&t, media_type, strlen (media_type)); - - if (http_tokenizer_next (&t, true) != HTTP_T_TOKEN) - goto end; - *type = xstrdup (t.string.str); - - if (http_tokenizer_next (&t, false) != HTTP_T_DELIMITER - || t.delimiter != '/') - goto end; - - if (http_tokenizer_next (&t, false) != HTTP_T_TOKEN) - goto end; - *subtype = xstrdup (t.string.str); - - while (true) - switch (http_tokenizer_next (&t, true)) - { - case HTTP_T_DELIMITER: - if (t.delimiter != ';') - goto end; - if (!http_parse_media_type_parameter (&t, parameters)) - goto end; - break; - case HTTP_T_EOF: - result = true; - default: - goto end; - } - -end: - http_tokenizer_free (&t); - return result; -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -struct http_protocol -{ - LIST_HEADER (struct http_protocol) - - char *name; ///< The protocol to upgrade to - char *version; ///< Version of the protocol, if any -}; - -static void -http_protocol_destroy (struct http_protocol *self) -{ - free (self->name); - free (self->version); - free (self); -} - -static bool -http_parse_upgrade (const char *upgrade, struct http_protocol **out) -{ - // HTTP grammar makes this more complicated than it should be - - bool result = false; - struct http_protocol *list = NULL; - struct http_protocol *tail = NULL; - - struct http_tokenizer t; - http_tokenizer_init (&t, upgrade, strlen (upgrade)); - - enum { - STATE_PROTOCOL_NAME, - STATE_SLASH, - STATE_PROTOCOL_VERSION, - STATE_EXPECT_COMMA - } state = STATE_PROTOCOL_NAME; - struct http_protocol *proto = NULL; - - while (true) - switch (state) - { - case STATE_PROTOCOL_NAME: - switch (http_tokenizer_next (&t, false)) - { - case HTTP_T_DELIMITER: - if (t.delimiter != ',') - goto end; - case HTTP_T_WHITESPACE: - break; - case HTTP_T_TOKEN: - proto = xcalloc (1, sizeof *proto); - proto->name = xstrdup (t.string.str); - LIST_APPEND_WITH_TAIL (list, tail, proto); - state = STATE_SLASH; - break; - case HTTP_T_EOF: - result = true; - default: - goto end; - } - break; - case STATE_SLASH: - switch (http_tokenizer_next (&t, false)) - { - case HTTP_T_DELIMITER: - if (t.delimiter == '/') - state = STATE_PROTOCOL_VERSION; - else if (t.delimiter == ',') - state = STATE_PROTOCOL_NAME; - else - goto end; - break; - case HTTP_T_WHITESPACE: - state = STATE_EXPECT_COMMA; - break; - case HTTP_T_EOF: - result = true; - default: - goto end; - } - break; - case STATE_PROTOCOL_VERSION: - switch (http_tokenizer_next (&t, false)) - { - case HTTP_T_TOKEN: - proto->version = xstrdup (t.string.str); - state = STATE_EXPECT_COMMA; - break; - default: - goto end; - } - break; - case STATE_EXPECT_COMMA: - switch (http_tokenizer_next (&t, false)) - { - case HTTP_T_DELIMITER: - if (t.delimiter != ',') - goto end; - state = STATE_PROTOCOL_NAME; - case HTTP_T_WHITESPACE: - break; - case HTTP_T_EOF: - result = true; - default: - goto end; - } - } - -end: - if (result) - *out = list; - else - LIST_FOR_EACH (struct http_protocol, iter, list) - http_protocol_destroy (iter); - - http_tokenizer_free (&t); - return result; -} +// Currently in sync, nothing to be moved. // --- libev helpers ----------------------------------------------------------- @@ -704,347 +75,31 @@ skip: if (write_queue_is_empty (queue)) ev_io_stop (EV_DEFAULT_ watcher); else - ev_io_start (EV_DEFAULT_ watcher); - return true; -} - -// --- Logging ----------------------------------------------------------------- - -static void -log_message_syslog (void *user_data, const char *quote, const char *fmt, - va_list ap) -{ - int prio = (int) (intptr_t) user_data; - - va_list va; - va_copy (va, ap); - int size = vsnprintf (NULL, 0, fmt, va); - va_end (va); - if (size < 0) - return; - - char buf[size + 1]; - if (vsnprintf (buf, sizeof buf, fmt, ap) >= 0) - syslog (prio, "%s%s", quote, buf); -} - -// --- FastCGI ----------------------------------------------------------------- - -// Constants from the FastCGI specification document - -#define FCGI_HEADER_LEN 8 - -#define FCGI_VERSION_1 1 -#define FCGI_NULL_REQUEST_ID 0 -#define FCGI_KEEP_CONN 1 - -enum fcgi_type -{ - FCGI_BEGIN_REQUEST = 1, - FCGI_ABORT_REQUEST = 2, - FCGI_END_REQUEST = 3, - FCGI_PARAMS = 4, - FCGI_STDIN = 5, - FCGI_STDOUT = 6, - FCGI_STDERR = 7, - FCGI_DATA = 8, - FCGI_GET_VALUES = 9, - FCGI_GET_VALUES_RESULT = 10, - FCGI_UNKNOWN_TYPE = 11, - FCGI_MAXTYPE = FCGI_UNKNOWN_TYPE -}; - -enum fcgi_role -{ - FCGI_RESPONDER = 1, - FCGI_AUTHORIZER = 2, - FCGI_FILTER = 3 -}; - -enum fcgi_protocol_status -{ - FCGI_REQUEST_COMPLETE = 0, - FCGI_CANT_MPX_CONN = 1, - FCGI_OVERLOADED = 2, - FCGI_UNKNOWN_ROLE = 3 -}; - -#define FCGI_MAX_CONNS "FCGI_MAX_CONNS" -#define FCGI_MAX_REQS "FCGI_MAX_REQS" -#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS" - -// - - Message stream parser - - - - - - - - - - - - - - - - - - - - - - - - - - - -struct fcgi_parser; - -typedef void (*fcgi_message_fn) - (const struct fcgi_parser *parser, void *user_data); - -enum fcgi_parser_state -{ - FCGI_READING_HEADER, ///< Reading the fixed header portion - FCGI_READING_CONTENT, ///< Reading the message content - FCGI_READING_PADDING ///< Reading the padding -}; - -struct fcgi_parser -{ - enum fcgi_parser_state state; ///< Parsing state - struct str input; ///< Input buffer - - // The next block of fields is considered public: - - uint8_t version; ///< FastCGI protocol version - uint8_t type; ///< FastCGI record type - uint16_t request_id; ///< FastCGI request ID - struct str content; ///< Message data - - uint16_t content_length; ///< Message content length - uint8_t padding_length; ///< Message padding length - - fcgi_message_fn on_message; ///< Callback on message - void *user_data; ///< User data -}; - -static void -fcgi_parser_init (struct fcgi_parser *self) -{ - memset (self, 0, sizeof *self); - str_init (&self->input); - str_init (&self->content); -} - -static void -fcgi_parser_free (struct fcgi_parser *self) -{ - str_free (&self->input); - str_free (&self->content); -} - -static void -fcgi_parser_unpack_header (struct fcgi_parser *self) -{ - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, self->input.str, self->input.len); - - bool success = true; - uint8_t reserved; - success &= msg_unpacker_u8 (&unpacker, &self->version); - success &= msg_unpacker_u8 (&unpacker, &self->type); - success &= msg_unpacker_u16 (&unpacker, &self->request_id); - success &= msg_unpacker_u16 (&unpacker, &self->content_length); - success &= msg_unpacker_u8 (&unpacker, &self->padding_length); - success &= msg_unpacker_u8 (&unpacker, &reserved); - hard_assert (success); - - str_remove_slice (&self->input, 0, unpacker.offset); -} - -static void -fcgi_parser_push (struct fcgi_parser *self, const void *data, size_t len) -{ - // This could be made considerably faster for high-throughput applications - // if we use a circular buffer instead of constantly calling memmove() - str_append_data (&self->input, data, len); - - while (true) - switch (self->state) - { - case FCGI_READING_HEADER: - if (self->input.len < FCGI_HEADER_LEN) - return; - - fcgi_parser_unpack_header (self); - self->state = FCGI_READING_CONTENT; - break; - case FCGI_READING_CONTENT: - if (self->input.len < self->content_length) - return; - - // Move an appropriate part of the input buffer to the content buffer - str_reset (&self->content); - str_append_data (&self->content, self->input.str, self->content_length); - str_remove_slice (&self->input, 0, self->content_length); - self->state = FCGI_READING_PADDING; - break; - case FCGI_READING_PADDING: - if (self->input.len < self->padding_length) - return; - - // Call the callback to further process the message - self->on_message (self, self->user_data); - - // Remove the padding from the input buffer - str_remove_slice (&self->input, 0, self->padding_length); - self->state = FCGI_READING_HEADER; - break; - } -} - -// - - Name-value pair parser - - - - - - - - - - - - - - - - - - - - - - - - - - -enum fcgi_nv_parser_state -{ - FCGI_NV_PARSER_NAME_LEN, ///< The first name length octet - FCGI_NV_PARSER_NAME_LEN_FULL, ///< Remaining name length octets - FCGI_NV_PARSER_VALUE_LEN, ///< The first value length octet - FCGI_NV_PARSER_VALUE_LEN_FULL, ///< Remaining value length octets - FCGI_NV_PARSER_NAME, ///< Reading the name - FCGI_NV_PARSER_VALUE ///< Reading the value -}; - -struct fcgi_nv_parser -{ - struct str_map *output; ///< Where the pairs will be stored - - enum fcgi_nv_parser_state state; ///< Parsing state - struct str input; ///< Input buffer - - uint32_t name_len; ///< Length of the name - uint32_t value_len; ///< Length of the value - - char *name; ///< The current name, 0-terminated - char *value; ///< The current value, 0-terminated -}; - -static void -fcgi_nv_parser_init (struct fcgi_nv_parser *self) -{ - memset (self, 0, sizeof *self); - str_init (&self->input); -} - -static void -fcgi_nv_parser_free (struct fcgi_nv_parser *self) -{ - str_free (&self->input); - free (self->name); - free (self->value); -} - -static void -fcgi_nv_parser_push (struct fcgi_nv_parser *self, const void *data, size_t len) -{ - // This could be optimized significantly; I'm not even trying - str_append_data (&self->input, data, len); - - while (true) - { - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, self->input.str, self->input.len); - - switch (self->state) - { - uint8_t len; - uint32_t len_full; - - case FCGI_NV_PARSER_NAME_LEN: - if (!msg_unpacker_u8 (&unpacker, &len)) - return; - - if (len >> 7) - self->state = FCGI_NV_PARSER_NAME_LEN_FULL; - else - { - self->name_len = len; - str_remove_slice (&self->input, 0, unpacker.offset); - self->state = FCGI_NV_PARSER_VALUE_LEN; - } - break; - case FCGI_NV_PARSER_NAME_LEN_FULL: - if (!msg_unpacker_u32 (&unpacker, &len_full)) - return; - - self->name_len = len_full & ~(1U << 31); - str_remove_slice (&self->input, 0, unpacker.offset); - self->state = FCGI_NV_PARSER_VALUE_LEN; - break; - case FCGI_NV_PARSER_VALUE_LEN: - if (!msg_unpacker_u8 (&unpacker, &len)) - return; - - if (len >> 7) - self->state = FCGI_NV_PARSER_VALUE_LEN_FULL; - else - { - self->value_len = len; - str_remove_slice (&self->input, 0, unpacker.offset); - self->state = FCGI_NV_PARSER_NAME; - } - break; - case FCGI_NV_PARSER_VALUE_LEN_FULL: - if (!msg_unpacker_u32 (&unpacker, &len_full)) - return; - - self->value_len = len_full & ~(1U << 31); - str_remove_slice (&self->input, 0, unpacker.offset); - self->state = FCGI_NV_PARSER_NAME; - break; - case FCGI_NV_PARSER_NAME: - if (self->input.len < self->name_len) - return; - - self->name = xmalloc (self->name_len + 1); - self->name[self->name_len] = '\0'; - memcpy (self->name, self->input.str, self->name_len); - str_remove_slice (&self->input, 0, self->name_len); - self->state = FCGI_NV_PARSER_VALUE; - break; - case FCGI_NV_PARSER_VALUE: - if (self->input.len < self->value_len) - return; - - self->value = xmalloc (self->value_len + 1); - self->value[self->value_len] = '\0'; - memcpy (self->value, self->input.str, self->value_len); - str_remove_slice (&self->input, 0, self->value_len); - self->state = FCGI_NV_PARSER_NAME_LEN; - - // The map takes ownership of the value - str_map_set (self->output, self->name, self->value); - free (self->name); - - self->name = NULL; - self->value = NULL; - break; - } - } + ev_io_start (EV_DEFAULT_ watcher); + return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// --- Logging ----------------------------------------------------------------- static void -fcgi_nv_convert_len (size_t len, struct str *output) +log_message_syslog (void *user_data, const char *quote, const char *fmt, + va_list ap) { - if (len < 0x80) - str_pack_u8 (output, len); - else - { - len |= (uint32_t) 1 << 31; - str_pack_u32 (output, len); - } -} + int prio = (int) (intptr_t) user_data; -static void -fcgi_nv_convert (struct str_map *map, struct str *output) -{ - struct str_map_iter iter; - str_map_iter_init (&iter, map); - while (str_map_iter_next (&iter)) - { - const char *name = iter.link->key; - const char *value = iter.link->data; - size_t name_len = iter.link->key_length; - size_t value_len = strlen (value); - - fcgi_nv_convert_len (name_len, output); - fcgi_nv_convert_len (value_len, output); - str_append_data (output, name, name_len); - str_append_data (output, value, value_len); - } + va_list va; + va_copy (va, ap); + int size = vsnprintf (NULL, 0, fmt, va); + va_end (va); + if (size < 0) + return; + + char buf[size + 1]; + if (vsnprintf (buf, sizeof buf, fmt, ap) >= 0) + syslog (prio, "%s%s", quote, buf); } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +// --- FastCGI ----------------------------------------------------------------- enum fcgi_request_state { @@ -1401,408 +456,8 @@ fcgi_muxer_push (struct fcgi_muxer *self, const void *data, size_t len) fcgi_parser_push (&self->parser, data, len); } -// --- SCGI -------------------------------------------------------------------- - -enum scgi_parser_state -{ - SCGI_READING_NETSTRING_LENGTH, ///< The length of the header netstring - SCGI_READING_NAME, ///< Header name - SCGI_READING_VALUE, ///< Header value - SCGI_READING_CONTENT ///< Incoming data -}; - -struct scgi_parser -{ - enum scgi_parser_state state; ///< Parsing state - struct str input; ///< Input buffer - - struct str_map headers; ///< Headers parsed - - size_t headers_len; ///< Length of the netstring contents - struct str name; ///< Header name so far - struct str value; ///< Header value so far - - /// Finished parsing request headers. - /// Return false to abort further processing of input. - bool (*on_headers_read) (void *user_data); - - /// Content available; len == 0 means end of file. - /// Return false to abort further processing of input. - bool (*on_content) (void *user_data, const void *data, size_t len); - - void *user_data; ///< User data passed to callbacks -}; - -static void -scgi_parser_init (struct scgi_parser *self) -{ - memset (self, 0, sizeof *self); - - str_init (&self->input); - str_map_init (&self->headers); - self->headers.free = free; - str_init (&self->name); - str_init (&self->value); -} - -static void -scgi_parser_free (struct scgi_parser *self) -{ - str_free (&self->input); - str_map_free (&self->headers); - str_free (&self->name); - str_free (&self->value); -} - -static bool -scgi_parser_push (struct scgi_parser *self, - const void *data, size_t len, struct error **e) -{ - if (!len) - { - if (self->state != SCGI_READING_CONTENT) - { - error_set (e, "premature EOF"); - return false; - } - - // Indicate end of file - return self->on_content (self->user_data, NULL, 0); - } - - // Notice that this madness is significantly harder to parse than FastCGI; - // this procedure could also be optimized significantly - str_append_data (&self->input, data, len); - - bool keep_running = true; - while (keep_running) - switch (self->state) - { - case SCGI_READING_NETSTRING_LENGTH: - { - if (self->input.len < 1) - return true; - - char digit = *self->input.str; - // XXX: this allows for omitting the netstring length altogether - if (digit == ':') - { - self->state = SCGI_READING_NAME; - break; - } - - if (digit < '0' || digit >= '9') - { - error_set (e, "invalid header netstring"); - return false; - } - - size_t new_len = self->headers_len * 10 + (digit - '0'); - if (new_len < self->headers_len) - { - error_set (e, "header netstring is too long"); - return false; - } - self->headers_len = new_len; - str_remove_slice (&self->input, 0, 1); - break; - } - case SCGI_READING_NAME: - { - if (self->input.len < 1) - return true; - - char c = *self->input.str; - if (!self->headers_len) - { - // The netstring is ending but we haven't finished parsing it, - // or the netstring doesn't end with a comma - if (self->name.len || c != ',') - { - error_set (e, "invalid header netstring"); - return false; - } - self->state = SCGI_READING_CONTENT; - keep_running = self->on_headers_read (self->user_data); - } - else if (c != '\0') - str_append_c (&self->name, c); - else - self->state = SCGI_READING_VALUE; - - str_remove_slice (&self->input, 0, 1); - break; - } - case SCGI_READING_VALUE: - { - if (self->input.len < 1) - return true; - - char c = *self->input.str; - if (!self->headers_len) - { - // The netstring is ending but we haven't finished parsing it - error_set (e, "invalid header netstring"); - return false; - } - else if (c != '\0') - str_append_c (&self->value, c); - else - { - // We've got a name-value pair, let's put it in the map - str_map_set (&self->headers, - self->name.str, str_steal (&self->value)); - - str_reset (&self->name); - str_init (&self->value); - - self->state = SCGI_READING_NAME; - } - - str_remove_slice (&self->input, 0, 1); - break; - } - case SCGI_READING_CONTENT: - keep_running = self->on_content - (self->user_data, self->input.str, self->input.len); - str_remove_slice (&self->input, 0, self->input.len); - return keep_running; - } - return false; -} - // --- WebSockets -------------------------------------------------------------- -#define WS_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - -#define SEC_WS_KEY "Sec-WebSocket-Key" -#define SEC_WS_ACCEPT "Sec-WebSocket-Accept" -#define SEC_WS_PROTOCOL "Sec-WebSocket-Protocol" -#define SEC_WS_EXTENSIONS "Sec-WebSocket-Extensions" -#define SEC_WS_VERSION "Sec-WebSocket-Version" - -#define WS_MAX_CONTROL_PAYLOAD_LEN 125 - -static char * -ws_encode_response_key (const char *key) -{ - char *response_key = xstrdup_printf ("%s" WS_GUID, key); - unsigned char hash[SHA_DIGEST_LENGTH]; - SHA1 ((unsigned char *) response_key, strlen (response_key), hash); - free (response_key); - - struct str base64; - str_init (&base64); - base64_encode (hash, sizeof hash, &base64); - return str_steal (&base64); -} - -enum ws_status -{ - // Named according to the meaning specified in RFC 6455, section 11.2 - - WS_STATUS_NORMAL_CLOSURE = 1000, - WS_STATUS_GOING_AWAY = 1001, - WS_STATUS_PROTOCOL_ERROR = 1002, - WS_STATUS_UNSUPPORTED_DATA = 1003, - WS_STATUS_INVALID_PAYLOAD_DATA = 1007, - WS_STATUS_POLICY_VIOLATION = 1008, - WS_STATUS_MESSAGE_TOO_BIG = 1009, - WS_STATUS_MANDATORY_EXTENSION = 1010, - WS_STATUS_INTERNAL_SERVER_ERROR = 1011, - - // Reserved for internal usage - WS_STATUS_NO_STATUS_RECEIVED = 1005, - WS_STATUS_ABNORMAL_CLOSURE = 1006, - WS_STATUS_TLS_HANDSHAKE = 1015 -}; - -// - - Frame parser - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -enum ws_parser_state -{ - WS_PARSER_FIXED, ///< Parsing fixed length part - WS_PARSER_PAYLOAD_LEN_16, ///< Parsing extended payload length - WS_PARSER_PAYLOAD_LEN_64, ///< Parsing extended payload length - WS_PARSER_MASK, ///< Parsing masking-key - WS_PARSER_PAYLOAD ///< Parsing payload -}; - -enum ws_opcode -{ - // Non-control - WS_OPCODE_CONT = 0, - WS_OPCODE_TEXT = 1, - WS_OPCODE_BINARY = 2, - - // Control - WS_OPCODE_CLOSE = 8, - WS_OPCODE_PING = 9, - WS_OPCODE_PONG = 10 -}; - -static bool -ws_is_control_frame (int opcode) -{ - return opcode >= WS_OPCODE_CLOSE; -} - -struct ws_parser -{ - struct str input; ///< External input buffer - enum ws_parser_state state; ///< Parsing state - - unsigned is_fin : 1; ///< Final frame of a message? - unsigned is_masked : 1; ///< Is the frame masked? - unsigned reserved_1 : 1; ///< Reserved - unsigned reserved_2 : 1; ///< Reserved - unsigned reserved_3 : 1; ///< Reserved - enum ws_opcode opcode; ///< Opcode - uint32_t mask; ///< Frame mask - uint64_t payload_len; ///< Payload length - - bool (*on_frame_header) (void *user_data, const struct ws_parser *self); - - /// Callback for when a message is successfully parsed. - /// The actual payload is stored in "input", of length "payload_len". - bool (*on_frame) (void *user_data, const struct ws_parser *self); - - void *user_data; ///< User data for callbacks -}; - -static void -ws_parser_init (struct ws_parser *self) -{ - memset (self, 0, sizeof *self); - str_init (&self->input); -} - -static void -ws_parser_free (struct ws_parser *self) -{ - str_free (&self->input); -} - -static void -ws_parser_unmask (struct ws_parser *self) -{ - // This could be made faster. For example by reading the mask in - // native byte ordering and applying it directly here. - - uint64_t end = self->payload_len & ~(uint64_t) 3; - for (uint64_t i = 0; i < end; i += 4) - { - self->input.str[i + 3] ^= self->mask & 0xFF; - self->input.str[i + 2] ^= (self->mask >> 8) & 0xFF; - self->input.str[i + 1] ^= (self->mask >> 16) & 0xFF; - self->input.str[i ] ^= (self->mask >> 24) & 0xFF; - } - - switch (self->payload_len - end) - { - case 3: - self->input.str[end + 2] ^= (self->mask >> 8) & 0xFF; - case 2: - self->input.str[end + 1] ^= (self->mask >> 16) & 0xFF; - case 1: - self->input.str[end ] ^= (self->mask >> 24) & 0xFF; - break; - } -} - -static bool -ws_parser_push (struct ws_parser *self, const void *data, size_t len) -{ - bool success = false; - str_append_data (&self->input, data, len); - - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, self->input.str, self->input.len); - - while (true) - switch (self->state) - { - uint8_t u8; - uint16_t u16; - - case WS_PARSER_FIXED: - if (unpacker.len - unpacker.offset < 2) - goto need_data; - - (void) msg_unpacker_u8 (&unpacker, &u8); - self->is_fin = (u8 >> 7) & 1; - self->reserved_1 = (u8 >> 6) & 1; - self->reserved_2 = (u8 >> 5) & 1; - self->reserved_3 = (u8 >> 4) & 1; - self->opcode = u8 & 15; - - (void) msg_unpacker_u8 (&unpacker, &u8); - self->is_masked = (u8 >> 7) & 1; - self->payload_len = u8 & 127; - - if (self->payload_len == 127) - self->state = WS_PARSER_PAYLOAD_LEN_64; - else if (self->payload_len == 126) - self->state = WS_PARSER_PAYLOAD_LEN_16; - else - self->state = WS_PARSER_MASK; - break; - - case WS_PARSER_PAYLOAD_LEN_16: - if (!msg_unpacker_u16 (&unpacker, &u16)) - goto need_data; - self->payload_len = u16; - - self->state = WS_PARSER_MASK; - break; - - case WS_PARSER_PAYLOAD_LEN_64: - if (!msg_unpacker_u64 (&unpacker, &self->payload_len)) - goto need_data; - - self->state = WS_PARSER_MASK; - break; - - case WS_PARSER_MASK: - if (!self->is_masked) - goto end_of_header; - if (!msg_unpacker_u32 (&unpacker, &self->mask)) - goto need_data; - - end_of_header: - self->state = WS_PARSER_PAYLOAD; - if (!self->on_frame_header (self->user_data, self)) - goto fail; - break; - - case WS_PARSER_PAYLOAD: - // Move the buffer so that payload data is at the front - str_remove_slice (&self->input, 0, unpacker.offset); - - // And continue unpacking frames past the payload - msg_unpacker_init (&unpacker, self->input.str, self->input.len); - unpacker.offset = self->payload_len; - - if (self->input.len < self->payload_len) - goto need_data; - if (self->is_masked) - ws_parser_unmask (self); - if (!self->on_frame (self->user_data, self)) - goto fail; - - self->state = WS_PARSER_FIXED; - break; - } - -need_data: - success = true; -fail: - str_remove_slice (&self->input, 0, unpacker.offset); - return success; -} - -// - - Server handler - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // WebSockets aren't CGI-compatible, therefore we must handle the initial HTTP // handshake ourselves. Luckily it's not too much of a bother with http-parser. // Typically there will be a normal HTTP server in front of us, proxying the @@ -2016,7 +671,7 @@ ws_handler_on_frame (void *user_data, const struct ws_parser *parser) } bool result = self->on_message (self->user_data, self->message_opcode, - self->parser.input.str, self->parser.payload_len); + self->message_data.str, self->message_data.len); str_reset (&self->message_data); return result; } @@ -3643,152 +2298,6 @@ lock_pid_file (struct server_context *ctx, struct error **e) // --- Tests ------------------------------------------------------------------- -static void -test_utf8 (void) -{ - const char valid [] = "2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm"; - const char invalid[] = "\xf0\x90\x28\xbc"; - soft_assert ( utf8_validate (valid, sizeof valid)); - soft_assert (!utf8_validate (invalid, sizeof invalid)); -} - -static void -test_base64 (void) -{ - char data[65]; - for (size_t i = 0; i < N_ELEMENTS (data); i++) - data[i] = i; - - struct str encoded; str_init (&encoded); - struct str decoded; str_init (&decoded); - - base64_encode (data, sizeof data, &encoded); - soft_assert (base64_decode (encoded.str, false, &decoded)); - soft_assert (decoded.len == sizeof data); - soft_assert (!memcmp (decoded.str, data, sizeof data)); - - str_free (&encoded); - str_free (&decoded); -} - -static void -test_http_parser (void) -{ - struct str_map parameters; - str_map_init (¶meters); - parameters.key_xfrm = tolower_ascii_strxfrm; - - char *type = NULL; - char *subtype = NULL; - soft_assert (http_parse_media_type ("TEXT/html; CHARset=\"utf\\-8\"", - &type, &subtype, ¶meters)); - soft_assert (!strcasecmp_ascii (type, "text")); - soft_assert (!strcasecmp_ascii (subtype, "html")); - soft_assert (parameters.len == 1); - soft_assert (!strcmp (str_map_find (¶meters, "charset"), "utf-8")); - str_map_free (¶meters); - - struct http_protocol *protocols; - soft_assert (http_parse_upgrade ("websocket, HTTP/2.0, , ", &protocols)); - - soft_assert (!strcmp (protocols->name, "websocket")); - soft_assert (!protocols->version); - - soft_assert (!strcmp (protocols->next->name, "HTTP")); - soft_assert (!strcmp (protocols->next->version, "2.0")); - - soft_assert (!protocols->next->next); - - LIST_FOR_EACH (struct http_protocol, iter, protocols) - http_protocol_destroy (iter); -} - -static bool -test_scgi_parser_on_headers_read (void *user_data) -{ - struct scgi_parser *parser = user_data; - soft_assert (parser->headers.len == 4); - soft_assert (!strcmp (str_map_find (&parser->headers, - "CONTENT_LENGTH"), "27")); - soft_assert (!strcmp (str_map_find (&parser->headers, - "SCGI"), "1")); - soft_assert (!strcmp (str_map_find (&parser->headers, - "REQUEST_METHOD"), "POST")); - soft_assert (!strcmp (str_map_find (&parser->headers, - "REQUEST_URI"), "/deepthought")); - return true; -} - -static bool -test_scgi_parser_on_content (void *user_data, const void *data, size_t len) -{ - (void) user_data; - soft_assert (!strncmp (data, "What is the answer to life?", len)); - return true; -} - -static void -test_scgi_parser (void) -{ - struct scgi_parser parser; - scgi_parser_init (&parser); - parser.on_headers_read = test_scgi_parser_on_headers_read; - parser.on_content = test_scgi_parser_on_content; - parser.user_data = &parser; - - // This is an example straight from the specification - const char example[] = - "70:" - "CONTENT_LENGTH" "\0" "27" "\0" - "SCGI" "\0" "1" "\0" - "REQUEST_METHOD" "\0" "POST" "\0" - "REQUEST_URI" "\0" "/deepthought" "\0" - "," - "What is the answer to life?"; - - soft_assert (scgi_parser_push (&parser, example, sizeof example, NULL)); - scgi_parser_free (&parser); -} - -static bool -test_websockets_on_frame_header (void *user_data, const struct ws_parser *self) -{ - (void) user_data; - soft_assert (self->is_fin); - soft_assert (self->is_masked); - soft_assert (self->opcode == WS_OPCODE_TEXT); - return true; -} - -static bool -test_websockets_on_frame (void *user_data, const struct ws_parser *self) -{ - (void) user_data; - soft_assert (self->input.len == self->payload_len); - soft_assert (!strncmp (self->input.str, "Hello", self->input.len)); - return true; -} - -static void -test_websockets (void) -{ - char *accept = ws_encode_response_key ("dGhlIHNhbXBsZSBub25jZQ=="); - soft_assert (!strcmp (accept, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")); - free (accept); - - struct ws_parser parser; - ws_parser_init (&parser); - parser.on_frame_header = test_websockets_on_frame_header; - parser.on_frame = test_websockets_on_frame; - parser.user_data = &parser; - - const char frame[] = "\x81\x85\x37\xfa\x21\x3d\x7f\x9f\x4d\x51\x58"; - soft_assert (ws_parser_push (&parser, frame, sizeof frame - 1)); - ws_parser_free (&parser); - - // TODO: test the server handler (happy path) -} - static void test_misc (void) { @@ -3808,15 +2317,10 @@ test_main (int argc, char *argv[]) struct test test; test_init (&test, argc, argv); - test_add_simple (&test, "/utf-8", NULL, test_utf8); - test_add_simple (&test, "/base64", NULL, test_base64); - test_add_simple (&test, "/http-parser", NULL, test_http_parser); - test_add_simple (&test, "/scgi-parser", NULL, test_scgi_parser); - test_add_simple (&test, "/websockets", NULL, test_websockets); - test_add_simple (&test, "/misc", NULL, test_misc); // TODO: write more tests + // TODO: test the server handler (happy path) return test_run (&test); } diff --git a/liberty b/liberty index 0876458..8c6d187 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 087645848baec5e59e4296817850bd5dd240cbb2 +Subproject commit 8c6d18757d2d4135963f3dbab6d2d5ec8c8b6af3 -- cgit v1.2.3-54-g00ecf From af3cb3aabad6b236dda5f421c9b694864a02883e Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sat, 16 Jan 2016 06:41:31 +0100 Subject: Bump liberty --- demo-json-rpc-server.c | 12 ++++++------ liberty | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'liberty') diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index a65693d..ab86c59 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -1136,7 +1136,7 @@ ws_handler_push (struct ws_handler *self, const void *data, size_t len) // --- Server ------------------------------------------------------------------ -static struct config_item g_config_table[] = +static struct simple_config_item g_config_table[] = { { "bind_host", NULL, "Address of the server" }, { "port_fastcgi", "9000", "Port to bind for FastCGI" }, @@ -1176,7 +1176,7 @@ server_context_init (struct server_context *self) memset (self, 0, sizeof *self); str_map_init (&self->config); - load_config_defaults (&self->config, g_config_table); + simple_config_load_defaults (&self->config, g_config_table); ev_timer_init (&self->quit_timeout_watcher, on_quit_timeout, 0., 0.); self->quit_timeout_watcher.data = self; } @@ -1583,7 +1583,7 @@ canonicalize_url_path (const char *path) // XXX: this strips any slashes at the end struct str_vector v; str_vector_init (&v); - split_str_ignore_empty (path, '/', &v); + cstr_split_ignore_empty (path, '/', &v); struct str_vector canonical; str_vector_init (&canonical); @@ -2383,7 +2383,7 @@ get_ports_from_config (struct server_context *ctx, { const char *ports; if ((ports = str_map_find (&ctx->config, key))) - split_str_ignore_empty (ports, ',', out); + cstr_split_ignore_empty (ports, ',', out); } static bool @@ -2588,7 +2588,7 @@ parse_program_arguments (int argc, char **argv) printf (PROGRAM_NAME " " PROGRAM_VERSION "\n"); exit (EXIT_SUCCESS); case 'w': - call_write_default_config (optarg, g_config_table); + call_simple_config_write_default (optarg, g_config_table); exit (EXIT_SUCCESS); default: print_error ("wrong options"); @@ -2618,7 +2618,7 @@ main (int argc, char *argv[]) server_context_init (&ctx); struct error *e = NULL; - if (!read_config_file (&ctx.config, &e)) + if (!simple_config_update_from_file (&ctx.config, &e)) { print_error ("error loading configuration: %s", e->message); error_free (e); diff --git a/liberty b/liberty index 8c6d187..8a9a282 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 8c6d18757d2d4135963f3dbab6d2d5ec8c8b6af3 +Subproject commit 8a9a28231bba6334c383dca59f7eccd1e5075693 -- cgit v1.2.3-54-g00ecf From 8b66a3f074e614c678ff8d56f239cb6f1a50deab Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 17 Jan 2016 04:42:16 +0100 Subject: Bump liberty --- demo-json-rpc-server.c | 55 ++++---------------------------------------------- liberty | 2 +- 2 files changed, 5 insertions(+), 52 deletions(-) (limited to 'liberty') diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index 00fdb4b..baa40dd 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -49,10 +49,10 @@ enum { PIPE_READ, PIPE_WRITE }; // --- libev helpers ----------------------------------------------------------- static bool -flush_queue (write_queue_t *queue, ev_io *watcher) +flush_queue (struct write_queue *queue, ev_io *watcher) { struct iovec vec[queue->len], *vec_iter = vec; - for (write_req_t *iter = queue->head; iter; iter = iter->next) + LIST_FOR_EACH (struct write_req, iter, queue->head) *vec_iter++ = iter->data; ssize_t written; @@ -1755,7 +1755,7 @@ struct client struct server_context *ctx; ///< Server context int socket_fd; ///< The TCP socket - write_queue_t write_queue; ///< Write queue + struct write_queue write_queue; ///< Write queue ev_io read_watcher; ///< The socket can be read from ev_io write_watcher; ///< The socket can be written to @@ -1785,7 +1785,7 @@ client_free (struct client *self) static void client_write (struct client *self, const void *data, size_t len) { - write_req_t *req = xcalloc (1, sizeof *req); + struct write_req *req = xcalloc (1, sizeof *req); req->data.iov_base = memcpy (xmalloc (len), data, len); req->data.iov_len = len; @@ -2434,53 +2434,6 @@ setup_listen_fds (struct server_context *ctx, struct error **e) return true; } -static int -lock_pid_file (const char *path, struct error **e) -{ - // When using XDG_RUNTIME_DIR, the file needs to either have its - // access time bumped every 6 hours, or have the sticky bit set - int fd = open (path, O_RDWR | O_CREAT, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH /* 644 */ | S_ISVTX /* sticky */); - if (fd < 0) - { - error_set (e, "can't open `%s': %s", path, strerror (errno)); - return -1; - } - - set_cloexec (fd); - - struct flock lock = - { - .l_type = F_WRLCK, - .l_start = 0, - .l_whence = SEEK_SET, - .l_len = 0, - }; - if (fcntl (fd, F_SETLK, &lock)) - { - error_set (e, "can't lock `%s': %s", path, strerror (errno)); - xclose (fd); - return -1; - } - - struct str pid; - str_init (&pid); - str_append_printf (&pid, "%ld", (long) getpid ()); - - if (ftruncate (fd, 0) - || write (fd, pid.str, pid.len) != (ssize_t) pid.len) - { - error_set (e, "can't write to `%s': %s", path, strerror (errno)); - xclose (fd); - return -1; - } - str_free (&pid); - - // Intentionally not closing the file descriptor; it must stay alive - // for the entire life of the application - return fd; -} - static bool app_lock_pid_file (struct server_context *ctx, struct error **e) { diff --git a/liberty b/liberty index 8a9a282..f213a76 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 8a9a28231bba6334c383dca59f7eccd1e5075693 +Subproject commit f213a76ad494efe150a786b195a744e4b87c5ca9 -- cgit v1.2.3-54-g00ecf From 0ec06857149d17ad0e86bb66f2fe9418bed13d8c Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 5 Feb 2017 22:44:01 +0100 Subject: Bump liberty --- demo-json-rpc-server.c | 56 +++++++++++++++++++++++++------------------------- liberty | 2 +- 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'liberty') diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index 10fe925..88f1adc 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -939,20 +939,20 @@ ws_handler_http_responsev (struct ws_handler *self, static void ws_handler_http_response (struct ws_handler *self, const char *status, ...) { - struct str_vector v; - str_vector_init (&v); + struct strv v; + strv_init (&v); va_list ap; va_start (ap, status); const char *s; while ((s = va_arg (ap, const char *))) - str_vector_add (&v, s); + strv_append (&v, s); va_end (ap); ws_handler_http_responsev (self, status, v.vector); - str_vector_free (&v); + strv_free (&v); } #define FAIL_HANDSHAKE(status, ...) \ @@ -1020,16 +1020,16 @@ ws_handler_finish_handshake (struct ws_handler *self) if (strcmp (version, "13")) FAIL_HANDSHAKE (HTTP_400_BAD_REQUEST, SEC_WS_VERSION ": 13", NULL); - struct str_vector fields; - str_vector_init (&fields); + struct strv fields; + strv_init (&fields); - str_vector_add_args (&fields, + strv_append_args (&fields, "Upgrade: websocket", "Connection: Upgrade", NULL); char *response_key = ws_encode_response_key (key); - str_vector_add_owned (&fields, + strv_append_owned (&fields, xstrdup_printf (SEC_WS_ACCEPT ": %s", response_key)); free (response_key); @@ -1038,7 +1038,7 @@ ws_handler_finish_handshake (struct ws_handler *self) ws_handler_http_responsev (self, HTTP_101_SWITCHING_PROTOCOLS, fields.vector); - str_vector_free (&fields); + strv_free (&fields); ev_timer_init (&self->ping_timer, ws_handler_on_ping_timer, self->ping_interval, 0); @@ -1580,15 +1580,15 @@ static char * canonicalize_url_path (const char *path) { // XXX: this strips any slashes at the end - struct str_vector v; - str_vector_init (&v); - cstr_split_ignore_empty (path, '/', &v); + struct strv v; + strv_init (&v); + cstr_split (path, "/", true, &v); - struct str_vector canonical; - str_vector_init (&canonical); + struct strv canonical; + strv_init (&canonical); // So that the joined path always begins with a slash - str_vector_add (&canonical, ""); + strv_append (&canonical, ""); for (size_t i = 0; i < v.len; i++) { @@ -1597,15 +1597,15 @@ canonicalize_url_path (const char *path) continue; if (strcmp (dir, "..")) - str_vector_add (&canonical, dir); + strv_append (&canonical, dir); else if (canonical.len > 1) // ".." never goes above the root - str_vector_remove (&canonical, canonical.len - 1); + strv_remove (&canonical, canonical.len - 1); } - str_vector_free (&v); + strv_free (&v); - char *joined = join_str_vector (&canonical, '/'); - str_vector_free (&canonical); + char *joined = strv_join (&canonical, "/"); + strv_free (&canonical); return joined; } @@ -2382,11 +2382,11 @@ listener_add (struct server_context *ctx, const char *host, const char *port, static void get_ports_from_config (struct server_context *ctx, - const char *key, struct str_vector *out) + const char *key, struct strv *out) { const char *ports; if ((ports = str_map_find (&ctx->config, key))) - cstr_split_ignore_empty (ports, ',', out); + cstr_split (ports, ",", true, out); } static bool @@ -2398,9 +2398,9 @@ setup_listen_fds (struct server_context *ctx, struct error **e) .ai_flags = AI_PASSIVE, }; - struct str_vector ports_fcgi; str_vector_init (&ports_fcgi); - struct str_vector ports_scgi; str_vector_init (&ports_scgi); - struct str_vector ports_ws; str_vector_init (&ports_ws); + struct strv ports_fcgi; strv_init (&ports_fcgi); + struct strv ports_scgi; strv_init (&ports_scgi); + struct strv ports_ws; strv_init (&ports_ws); get_ports_from_config (ctx, "port_fastcgi", &ports_fcgi); get_ports_from_config (ctx, "port_scgi", &ports_scgi); @@ -2420,9 +2420,9 @@ setup_listen_fds (struct server_context *ctx, struct error **e) listener_add (ctx, bind_host, ports_ws.vector[i], &gai_hints, client_ws_create); - str_vector_free (&ports_fcgi); - str_vector_free (&ports_scgi); - str_vector_free (&ports_ws); + strv_free (&ports_fcgi); + strv_free (&ports_scgi); + strv_free (&ports_ws); if (!ctx->n_listeners) { diff --git a/liberty b/liberty index f213a76..084e964 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit f213a76ad494efe150a786b195a744e4b87c5ca9 +Subproject commit 084e964286bfcd13ee6a25a2ee35dfba9da1072e -- cgit v1.2.3-54-g00ecf From d35e733c6ef9ac43639c1d1361446ecb3e94b6f6 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Mon, 6 Feb 2017 19:47:24 +0100 Subject: Bump liberty Fixing a bug in the WebSocket frame parser. --- liberty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'liberty') diff --git a/liberty b/liberty index 084e964..9afcb33 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 084e964286bfcd13ee6a25a2ee35dfba9da1072e +Subproject commit 9afcb337ada91f87aa1a566ec3feba1a12bc9287 -- cgit v1.2.3-54-g00ecf From 5e88608286089cbcce81fd8fa9217cf77a1f7576 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Tue, 20 Jun 2017 14:04:40 +0200 Subject: Bump liberty and http-parser --- http-parser | 2 +- liberty | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'liberty') diff --git a/http-parser b/http-parser index d547f3b..1b79aba 160000 --- a/http-parser +++ b/http-parser @@ -1 +1 @@ -Subproject commit d547f3b1a98ed07fdcdaf401a8cbc5fffe9bfa6c +Subproject commit 1b79abab34d4763c0467f1173a406ad2817c1635 diff --git a/liberty b/liberty index 9afcb33..1dcd259 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 9afcb337ada91f87aa1a566ec3feba1a12bc9287 +Subproject commit 1dcd259d0506b9e2de3715bdf07144b22f57903a -- cgit v1.2.3-54-g00ecf From 131debe985199e3d261a985b2055a86fc4bd3fdd Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Sun, 24 Jun 2018 00:40:10 +0200 Subject: Bump liberty --- .gitmodules | 2 +- demo-json-rpc-server.c | 106 ++++++++++++++++++++----------------------------- liberty | 2 +- 3 files changed, 44 insertions(+), 66 deletions(-) (limited to 'liberty') diff --git a/.gitmodules b/.gitmodules index c8d5acf..1a41faf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ [submodule "liberty"] path = liberty - url = git://github.com/pjanouch/liberty.git + url = https://git.janouch.name/p/liberty.git [submodule "http-parser"] path = http-parser url = https://github.com/joyent/http-parser.git diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index 10c808e..0cfb13b 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -144,8 +144,7 @@ fcgi_muxer_send (struct fcgi_muxer *self, { hard_assert (len <= UINT16_MAX); - struct str message; - str_init (&message); + struct str message = str_make (); str_pack_u8 (&message, FCGI_VERSION_1); str_pack_u8 (&message, type); @@ -177,10 +176,9 @@ fcgi_request_init (struct fcgi_request *self) { memset (self, 0, sizeof *self); - str_map_init (&self->headers); - self->headers.free = free; + self->headers = str_map_make (free); - fcgi_nv_parser_init (&self->hdr_parser); + self->hdr_parser = fcgi_nv_parser_make (); self->hdr_parser.output = &self->headers; } @@ -275,17 +273,15 @@ static void fcgi_muxer_on_get_values (struct fcgi_muxer *self, const struct fcgi_parser *parser) { - struct str_map values; str_map_init (&values); values.free = free; - struct str_map response; str_map_init (&response); response.free = free; + struct str_map values = str_map_make (free); + struct str_map response = str_map_make (free); - struct fcgi_nv_parser nv_parser; - fcgi_nv_parser_init (&nv_parser); + struct fcgi_nv_parser nv_parser = fcgi_nv_parser_make (); nv_parser.output = &values; fcgi_nv_parser_push (&nv_parser, parser->content.str, parser->content.len); - struct str_map_iter iter; - str_map_iter_init (&iter, &values); + struct str_map_iter iter = str_map_iter_make (&values); while (str_map_iter_next (&iter)) { const char *key = iter.link->key; @@ -297,8 +293,7 @@ fcgi_muxer_on_get_values str_map_set (&response, key, xstrdup ("1")); } - struct str content; - str_init (&content); + struct str content = str_make (); fcgi_nv_convert (&response, &content); fcgi_muxer_send (self, FCGI_GET_VALUES_RESULT, parser->request_id, content.str, content.len); @@ -312,8 +307,8 @@ static void fcgi_muxer_on_begin_request (struct fcgi_muxer *self, const struct fcgi_parser *parser) { - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, parser->content.str, parser->content.len); + struct msg_unpacker unpacker = + msg_unpacker_make (parser->content.str, parser->content.len); uint16_t role; uint8_t flags; @@ -435,7 +430,7 @@ fcgi_muxer_on_message (const struct fcgi_parser *parser, void *user_data) static void fcgi_muxer_init (struct fcgi_muxer *self) { - fcgi_parser_init (&self->parser); + self->parser = fcgi_parser_make (); self->parser.on_message = fcgi_muxer_on_message; self->parser.user_data = self; } @@ -554,8 +549,7 @@ static void ws_handler_close (struct ws_handler *self, enum ws_status close_code, const char *reason, size_t len) { - struct str payload; - str_init (&payload); + struct str payload = str_make (); str_pack_u16 (&payload, close_code); // XXX: maybe accept a null-terminated string on input? Has to be UTF-8 a/w str_append_data (&payload, reason, len); @@ -590,8 +584,7 @@ ws_handler_send (struct ws_handler *self, if (!soft_assert (self->state == WS_HANDLER_OPEN)) return; - struct str header; - str_init (&header); + struct str header = str_make (); str_pack_u8 (&header, 0x80 | (opcode & 0x0F)); if (len > UINT16_MAX) @@ -639,8 +632,8 @@ static bool ws_handler_on_protocol_close (struct ws_handler *self, const struct ws_parser *parser) { - struct msg_unpacker unpacker; - msg_unpacker_init (&unpacker, parser->input.str, parser->payload_len); + struct msg_unpacker unpacker = + msg_unpacker_make (parser->input.str, parser->payload_len); char *reason = NULL; uint16_t close_code = WS_STATUS_NO_STATUS_RECEIVED; @@ -775,21 +768,20 @@ ws_handler_init (struct ws_handler *self) http_parser_init (&self->hp, HTTP_REQUEST); self->hp.data = self; - str_init (&self->field); - str_init (&self->value); - str_map_init (&self->headers); - self->headers.free = free; + self->field = str_make (); + self->value = str_make (); + self->headers = str_map_make (free); self->headers.key_xfrm = tolower_ascii_strxfrm; - str_init (&self->url); + self->url = str_make (); ev_timer_init (&self->handshake_timeout_watcher, ws_handler_on_handshake_timeout, 0., 0.); self->handshake_timeout_watcher.data = self; - ws_parser_init (&self->parser); + self->parser = ws_parser_make (); self->parser.on_frame_header = ws_handler_on_frame_header; self->parser.on_frame = ws_handler_on_frame; self->parser.user_data = self; - str_init (&self->message_data); + self->message_data = str_make (); ev_timer_init (&self->ping_timer, ws_handler_on_ping_timer, 0., 0.); @@ -927,8 +919,7 @@ ws_handler_http_responsev (struct ws_handler *self, { hard_assert (status != NULL); - struct str response; - str_init (&response); + struct str response = str_make (); str_append_printf (&response, "HTTP/1.1 %s\r\n", status); while (*fields) @@ -943,8 +934,7 @@ ws_handler_http_responsev (struct ws_handler *self, static void ws_handler_http_response (struct ws_handler *self, const char *status, ...) { - struct strv v; - strv_init (&v); + struct strv v = strv_make (); va_list ap; va_start (ap, status); @@ -1015,8 +1005,7 @@ ws_handler_finish_handshake (struct ws_handler *self) if (!key) FAIL_HANDSHAKE (HTTP_400_BAD_REQUEST, NULL); - struct str tmp; - str_init (&tmp); + struct str tmp = str_make (); bool key_is_valid = base64_decode (key, false, &tmp) && tmp.len == 16; str_free (&tmp); if (!key_is_valid) @@ -1027,9 +1016,7 @@ ws_handler_finish_handshake (struct ws_handler *self) if (strcmp (version, "13")) FAIL_HANDSHAKE (HTTP_400_BAD_REQUEST, SEC_WS_VERSION ": 13", NULL); - struct strv fields; - strv_init (&fields); - + struct strv fields = strv_make (); strv_append_args (&fields, "Upgrade: websocket", "Connection: Upgrade", @@ -1181,7 +1168,7 @@ server_context_init (struct server_context *self) { memset (self, 0, sizeof *self); - str_map_init (&self->config); + self->config = str_map_make (NULL); simple_config_load_defaults (&self->config, g_config_table); ev_timer_init (&self->quit_timeout_watcher, on_quit_timeout, 3., 0.); self->quit_timeout_watcher.data = self; @@ -1260,9 +1247,7 @@ validate_json_rpc_content_type (const char *content_type) char *type = NULL; char *subtype = NULL; - struct str_map parameters; - str_map_init (¶meters); - parameters.free = free; + struct str_map parameters = str_map_make (free); parameters.key_xfrm = tolower_ascii_strxfrm; bool result = http_parse_media_type @@ -1503,8 +1488,7 @@ request_start (struct request *self, struct str_map *headers) } // Unable to serve the request - struct str response; - str_init (&response); + struct str response = str_make (); str_append (&response, "Status: 404 Not Found\n"); str_append (&response, "Content-Type: text/plain\n\n"); self->write_cb (self->user_data, response.str, response.len); @@ -1536,7 +1520,7 @@ request_handler_json_rpc_try_handle return false; struct str *buf = xcalloc (1, sizeof *buf); - str_init (buf); + *buf = str_make (); request->handler_data = buf; *continue_ = true; @@ -1554,8 +1538,7 @@ request_handler_json_rpc_push return true; } - struct str response; - str_init (&response); + struct str response = str_make (); str_append (&response, "Status: 200 OK\n"); str_append_printf (&response, "Content-Type: %s\n\n", "application/json"); process_json_rpc (request->ctx, buf->str, buf->len, &response); @@ -1587,12 +1570,10 @@ static char * canonicalize_url_path (const char *path) { // XXX: this strips any slashes at the end - struct strv v; - strv_init (&v); + struct strv v = strv_make (); cstr_split (path, "/", true, &v); - struct strv canonical; - strv_init (&canonical); + struct strv canonical = strv_make (); // So that the joined path always begins with a slash strv_append (&canonical, ""); @@ -1672,8 +1653,7 @@ request_handler_static_try_handle FILE *fp = fopen (path, "rb"); if (!fp) { - struct str response; - str_init (&response); + struct str response = str_make (); str_append (&response, "Status: 404 Not Found\n"); str_append (&response, "Content-Type: text/plain\n\n"); str_append_printf (&response, @@ -1699,8 +1679,7 @@ request_handler_static_try_handle if (!mime_type) mime_type = xstrdup ("application/octet_stream"); - struct str response; - str_init (&response); + struct str response = str_make (); str_append (&response, "Status: 200 OK\n"); str_append_printf (&response, "Content-Type: %s\n\n", mime_type); request->write_cb (request->user_data, response.str, response.len); @@ -1878,7 +1857,7 @@ client_init (EV_P_ struct client *self, int sock_fd) memset (self, 0, sizeof *self); self->ctx = ctx; - write_queue_init (&self->write_queue); + self->write_queue = write_queue_make (); set_blocking (sock_fd, false); self->socket_fd = sock_fd; @@ -2119,7 +2098,7 @@ client_scgi_create (EV_P_ int sock_fd) self->request.close_cb = client_scgi_close_cb; self->request.user_data = self; - scgi_parser_init (&self->parser); + self->parser = scgi_parser_make (); self->parser.on_headers_read = client_scgi_on_headers_read; self->parser.on_content = client_scgi_on_content; self->parser.user_data = self; @@ -2145,8 +2124,7 @@ client_ws_on_message (void *user_data, return false; } - struct str response; - str_init (&response); + struct str response = str_make (); process_json_rpc (self->client.ctx, data, len, &response); if (response.len) ws_handler_send (&self->handler, @@ -2410,9 +2388,9 @@ setup_listen_fds (struct server_context *ctx, struct error **e) .ai_flags = AI_PASSIVE, }; - struct strv ports_fcgi; strv_init (&ports_fcgi); - struct strv ports_scgi; strv_init (&ports_scgi); - struct strv ports_ws; strv_init (&ports_ws); + struct strv ports_fcgi = strv_make (); + struct strv ports_scgi = strv_make (); + struct strv ports_ws = strv_make (); get_ports_from_config (ctx, "port_fastcgi", &ports_fcgi); get_ports_from_config (ctx, "port_scgi", &ports_scgi); @@ -2588,8 +2566,8 @@ parse_program_arguments (int argc, char **argv) { 0, NULL, NULL, 0, NULL } }; - struct opt_handler oh; - opt_handler_init (&oh, argc, argv, opts, NULL, "JSON-RPC 2.0 demo server."); + struct opt_handler oh = + opt_handler_make (argc, argv, opts, NULL, "JSON-RPC 2.0 demo server."); int c; while ((c = opt_handler_get (&oh)) != -1) diff --git a/liberty b/liberty index 1dcd259..8ffe20c 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 1dcd259d0506b9e2de3715bdf07144b22f57903a +Subproject commit 8ffe20c0e83b52db1344fe91f57236be4c4cb504 -- cgit v1.2.3-54-g00ecf From 329fc9b88fa419ef2c3a32ccc4414dec223bd69d Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Thu, 11 Oct 2018 21:03:34 +0200 Subject: Bump liberty Eliminates some fall-through warnings. --- liberty | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'liberty') diff --git a/liberty b/liberty index 8ffe20c..9494e8e 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 8ffe20c0e83b52db1344fe91f57236be4c4cb504 +Subproject commit 9494e8e2affcd08b791d3ecf68985a8a3a310e55 -- cgit v1.2.3-54-g00ecf From d883f4cc71a1f9db5cc4cec2bc60df6cba1f8833 Mon Sep 17 00:00:00 2001 From: Přemysl Janouch Date: Thu, 18 Oct 2018 04:13:59 +0200 Subject: Finish the FastCGI backend Bump liberty, also fixing SCGI. --- demo-json-rpc-server.c | 154 ++++++++++++++++++++++++------------------------- liberty | 2 +- 2 files changed, 75 insertions(+), 81 deletions(-) (limited to 'liberty') diff --git a/demo-json-rpc-server.c b/demo-json-rpc-server.c index 60a7173..50e203f 100644 --- a/demo-json-rpc-server.c +++ b/demo-json-rpc-server.c @@ -194,6 +194,8 @@ fcgi_request_new (void) self->hdr_parser = fcgi_nv_parser_make (); self->hdr_parser.output = &self->headers; + + self->output_buffer = str_make (); return self; } @@ -208,40 +210,6 @@ fcgi_request_destroy (struct fcgi_request *self) free (self); } -static void -fcgi_request_push_params - (struct fcgi_request *self, const void *data, size_t len) -{ - if (self->state != FCGI_REQUEST_PARAMS) - { - // TODO: probably reject the request - return; - } - - if (len) - fcgi_nv_parser_push (&self->hdr_parser, data, len); - else - { - // TODO: probably check the state of the header parser - // TODO: request_start() can return false, end the request here? - (void) self->muxer->request_start_cb (self); - self->state = FCGI_REQUEST_STDIN; - } -} - -static void -fcgi_request_push_stdin - (struct fcgi_request *self, const void *data, size_t len) -{ - if (self->state != FCGI_REQUEST_STDIN) - { - // TODO: probably reject the request - return; - } - - self->muxer->request_push_cb (self, data, len); -} - static void fcgi_request_flush (struct fcgi_request *self) { @@ -294,36 +262,62 @@ fcgi_request_finish (struct fcgi_request *self) self->muxer->requests[self->request_id] = NULL; fcgi_request_destroy (self); - // TODO: tear down (shut down) the connection. This is called from: - // - // 1. client_fcgi_request_push <- request_push_cb - // <- fcgi_request_push_stdin <- fcgi_muxer_on_stdin - // <- fcgi_muxer_on_message <- fcgi_parser_push <- fcgi_muxer_push - // <- client_fcgi_push <- client_read_loop - // => in this case no close_cb may be called - // -> need to pass a false boolean aaall the way up, - // then client_fcgi_finalize eventually cleans up the rest - // - // 2. client_fcgi_request_close_cb <- request_finish - // => our direct caller must call fcgi_muxer::close_cb - // -> not very nice to delegate it there return !should_close; } +static bool +fcgi_request_push_params + (struct fcgi_request *self, const void *data, size_t len) +{ + if (self->state != FCGI_REQUEST_PARAMS) + { + print_debug ("FastCGI: expected %s, got %s", + STRINGIFY (FCGI_STDIN), STRINGIFY (FCGI_PARAMS)); + return false; + } + + if (len) + fcgi_nv_parser_push (&self->hdr_parser, data, len); + else + { + if (self->hdr_parser.state != FCGI_NV_PARSER_NAME_LEN) + print_debug ("FastCGI: request headers seem to be cut off"); + + self->state = FCGI_REQUEST_STDIN; + if (!self->muxer->request_start_cb (self)) + return fcgi_request_finish (self); + } + return true; +} + +static bool +fcgi_request_push_stdin + (struct fcgi_request *self, const void *data, size_t len) +{ + if (self->state != FCGI_REQUEST_STDIN) + { + print_debug ("FastCGI: expected %s, got %s", + STRINGIFY (FCGI_PARAMS), STRINGIFY (FCGI_STDIN)); + return false; + } + + return self->muxer->request_push_cb (self, data, len); +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -typedef void (*fcgi_muxer_handler_fn) +typedef bool (*fcgi_muxer_handler_fn) (struct fcgi_muxer *, const struct fcgi_parser *); -static void +static bool fcgi_muxer_on_get_values (struct fcgi_muxer *self, const struct fcgi_parser *parser) { if (parser->request_id != FCGI_NULL_REQUEST_ID) { - print_debug ("FastCGI: ignoring invalid %s message", + print_debug ("FastCGI: invalid %s message", STRINGIFY (FCGI_GET_VALUES)); - return; + return false; } struct str_map values = str_map_make (free); @@ -357,9 +351,10 @@ fcgi_muxer_on_get_values str_map_free (&values); str_map_free (&response); + return true; } -static void +static bool fcgi_muxer_on_begin_request (struct fcgi_muxer *self, const struct fcgi_parser *parser) { @@ -375,16 +370,17 @@ fcgi_muxer_on_begin_request if (!success) { - print_debug ("FastCGI: ignoring invalid %s message", + print_debug ("FastCGI: invalid %s message", STRINGIFY (FCGI_BEGIN_REQUEST)); - return; + return false; } struct fcgi_request *request = self->requests[parser->request_id]; if (parser->request_id == FCGI_NULL_REQUEST_ID || request) { - // TODO: fail - return; + print_debug ("FastCGI: unusable request ID in %s message", + STRINGIFY (FCGI_BEGIN_REQUEST)); + return false; } // We can only act as a responder, reject everything else up front @@ -392,7 +388,7 @@ fcgi_muxer_on_begin_request { fcgi_muxer_send_end_request (self, parser->request_id, 0, FCGI_UNKNOWN_ROLE); - return; + return true; } if (parser->request_id >= N_ELEMENTS (self->requests) @@ -400,7 +396,7 @@ fcgi_muxer_on_begin_request { fcgi_muxer_send_end_request (self, parser->request_id, 0, FCGI_OVERLOADED); - return; + return true; } request = fcgi_request_new (); @@ -410,9 +406,10 @@ fcgi_muxer_on_begin_request self->requests[parser->request_id] = request; self->active_requests++; + return true; } -static void +static bool fcgi_muxer_on_abort_request (struct fcgi_muxer *self, const struct fcgi_parser *parser) { @@ -421,15 +418,13 @@ fcgi_muxer_on_abort_request { print_debug ("FastCGI: received %s for an unknown request", STRINGIFY (FCGI_ABORT_REQUEST)); - return; + return true; // We might have just rejected it } - // TODO: abort the request: let it somehow produce FCGI_END_REQUEST, - // make sure to send an stdout EOF record - // TODO: and if that was not a FCGI_KEEP_CONN request, close the transport + return fcgi_request_finish (request); } -static void +static bool fcgi_muxer_on_params (struct fcgi_muxer *self, const struct fcgi_parser *parser) { struct fcgi_request *request = self->requests[parser->request_id]; @@ -437,14 +432,15 @@ fcgi_muxer_on_params (struct fcgi_muxer *self, const struct fcgi_parser *parser) { print_debug ("FastCGI: received %s for an unknown request", STRINGIFY (FCGI_PARAMS)); - return; + return true; // We might have just rejected it } - fcgi_request_push_params (request, + // This may immediately finish and delete the request, but that's fine + return fcgi_request_push_params (request, parser->content.str, parser->content.len); } -static void +static bool fcgi_muxer_on_stdin (struct fcgi_muxer *self, const struct fcgi_parser *parser) { struct fcgi_request *request = self->requests[parser->request_id]; @@ -452,15 +448,15 @@ fcgi_muxer_on_stdin (struct fcgi_muxer *self, const struct fcgi_parser *parser) { print_debug ("FastCGI: received %s for an unknown request", STRINGIFY (FCGI_STDIN)); - return; + return true; // We might have just rejected it } // At the end of the stream, a zero-length record is received - fcgi_request_push_stdin (request, + return fcgi_request_push_stdin (request, parser->content.str, parser->content.len); } -static void +static bool fcgi_muxer_on_message (const struct fcgi_parser *parser, void *user_data) { struct fcgi_muxer *self = user_data; @@ -468,8 +464,7 @@ fcgi_muxer_on_message (const struct fcgi_parser *parser, void *user_data) if (parser->version != FCGI_VERSION_1) { print_debug ("FastCGI: unsupported version %d", parser->version); - // TODO: also return false to stop processing on protocol error? - return; + return false; } static const fcgi_muxer_handler_fn handlers[] = @@ -489,10 +484,10 @@ fcgi_muxer_on_message (const struct fcgi_parser *parser, void *user_data) uint8_t content[8] = { parser->type }; fcgi_muxer_send (self, FCGI_UNKNOWN_TYPE, parser->request_id, content, sizeof content); - return; + return true; } - handler (self, parser); + return handler (self, parser); } static void @@ -520,10 +515,10 @@ fcgi_muxer_free (struct fcgi_muxer *self) fcgi_parser_free (&self->parser); } -static void +static bool fcgi_muxer_push (struct fcgi_muxer *self, const void *data, size_t len) { - fcgi_parser_push (&self->parser, data, len); + return fcgi_parser_push (&self->parser, data, len); } /// @} @@ -1574,7 +1569,7 @@ struct request /// Callback to write some CGI response data to the output void (*write_cb) (struct request *, const void *data, size_t len); - /// Callback to close the connection. + /// Callback to close the CGI response, simulates end of program execution. /// CALLING THIS MAY CAUSE THE REQUEST TO BE DESTROYED. void (*close_cb) (struct request *); }; @@ -1967,7 +1962,7 @@ client_destroy (struct client *self) static void client_write (struct client *self, const void *data, size_t len) { - if (!soft_assert (!self->flushing)) + if (!soft_assert (!self->flushing) || len == 0) return; struct write_req *req = xcalloc (1, sizeof *req); @@ -2206,8 +2201,7 @@ static bool client_fcgi_push (struct client *client, const void *data, size_t len) { FIND_CONTAINER (self, client, struct client_fcgi, client); - fcgi_muxer_push (&self->muxer, data, len); - return true; + return fcgi_muxer_push (&self->muxer, data, len); } static void diff --git a/liberty b/liberty index 9494e8e..bca7167 160000 --- a/liberty +++ b/liberty @@ -1 +1 @@ -Subproject commit 9494e8e2affcd08b791d3ecf68985a8a3a310e55 +Subproject commit bca7167d037d857448cb18243425d7c61de3bdd5 -- cgit v1.2.3-54-g00ecf