diff --git a/mio/bin/t03.c b/mio/bin/t03.c index 53a22e1..cacb24f 100644 --- a/mio/bin/t03.c +++ b/mio/bin/t03.c @@ -114,6 +114,13 @@ static int write_json_element (mio_jsonwr_t* jsonwr, const mio_bch_t* dptr, mio_ int main (int argc, char* argv[]) { mio_t* mio = MIO_NULL; + mio_bitmask_t o = 0; + int i; + + for (i = 1; i < argc; i++) + { + if (strcmp(argv[i], "--permit-word-key") == 0) o |= MIO_JSON_PERMITWORDKEY; + } mio = mio_open(MIO_NULL, 0, MIO_NULL, 512, MIO_NULL); if (!mio) @@ -131,6 +138,7 @@ int main (int argc, char* argv[]) json = mio_json_open(mio, 0); + mio_json_setoption (json, o); mio_json_setinstcb (json, on_json_inst, &pending); rem = 0; @@ -152,7 +160,7 @@ int main (int argc, char* argv[]) if ((x = mio_json_feed(json, buf, size + rem, &rem, 1)) <= -1) { mio_logbfmt (mio, MIO_LOG_STDOUT, "**** ERROR - %js ****\n", mio_geterrmsg(mio)); - break; + goto done; } if (x > 0) @@ -167,7 +175,10 @@ int main (int argc, char* argv[]) } mio_logbfmt (mio, MIO_LOG_STDOUT, "\n"); - if (pending) mio_logbfmt (mio, MIO_LOG_STDOUT, "**** ERROR - incomplete ****\n"); + //if (pending) mio_logbfmt (mio, MIO_LOG_STDOUT, "**** ERROR - incomplete ****\n"); + if (json->state_stack != &json->state_top) mio_logbfmt (mio, MIO_LOG_STDOUT, "**** ERROR - incomplete ****\n"); + + done: mio_json_close (json); } diff --git a/mio/lib/htrd.c b/mio/lib/htrd.c index bbfe04d..bc06dc8 100644 --- a/mio/lib/htrd.c +++ b/mio/lib/htrd.c @@ -434,14 +434,14 @@ mio_htrd_errnum_t mio_htrd_geterrnum (mio_htrd_t* htrd) return htrd->errnum; } -int mio_htrd_getopt (mio_htrd_t* htrd) +mio_bitmask_t mio_htrd_getoption (mio_htrd_t* htrd) { return htrd->option; } -void mio_htrd_setopt (mio_htrd_t* htrd, int opts) +void mio_htrd_setoption (mio_htrd_t* htrd, mio_bitmask_t mask) { - htrd->option = opts; + htrd->option = mask; } const mio_htrd_recbs_t* mio_htrd_getrecbs (mio_htrd_t* htrd) diff --git a/mio/lib/http-cgi.c b/mio/lib/http-cgi.c index 3fec3c4..01c3cf2 100644 --- a/mio/lib/http-cgi.c +++ b/mio/lib/http-cgi.c @@ -963,7 +963,7 @@ int mio_svc_htts_docgi (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r cgi->peer_htrd = mio_htrd_open(mio, MIO_SIZEOF(*cgi_peer)); if (MIO_UNLIKELY(!cgi->peer_htrd)) goto oops; - mio_htrd_setopt (cgi->peer_htrd, MIO_HTRD_SKIPINITIALLINE | MIO_HTRD_RESPONSE); + mio_htrd_setoption (cgi->peer_htrd, MIO_HTRD_SKIPINITIALLINE | MIO_HTRD_RESPONSE); mio_htrd_setrecbs (cgi->peer_htrd, &cgi_peer_htrd_recbs); cgi_peer = mio_htrd_getxtn(cgi->peer_htrd); diff --git a/mio/lib/http-svr.c b/mio/lib/http-svr.c index 858c47a..46913ba 100644 --- a/mio/lib/http-svr.c +++ b/mio/lib/http-svr.c @@ -64,7 +64,7 @@ static int init_client (mio_svc_htts_cli_t* cli, mio_dev_sck_t* sck) /* With MIO_HTRD_TRAILERS, htrd stores trailers in a separate place. * Otherwise, it is merged to the headers. */ - /*mio_htrd_setopt (cli->htrd, MIO_HTRD_REQUEST | MIO_HTRD_TRAILERS);*/ + /*mio_htrd_setoption (cli->htrd, MIO_HTRD_REQUEST | MIO_HTRD_TRAILERS);*/ cli->sbuf = mio_becs_open(sck->mio, 0, 2048); if (MIO_UNLIKELY(!cli->sbuf)) goto oops; diff --git a/mio/lib/http-thr.c b/mio/lib/http-thr.c index dfcb1e0..f6cd5f6 100644 --- a/mio/lib/http-thr.c +++ b/mio/lib/http-thr.c @@ -889,7 +889,7 @@ int mio_svc_htts_dothr (mio_svc_htts_t* htts, mio_dev_sck_t* csck, mio_htre_t* r thr_state->peer_htrd = mio_htrd_open(mio, MIO_SIZEOF(*thr_peer)); if (MIO_UNLIKELY(!thr_state->peer_htrd)) goto oops; - mio_htrd_setopt (thr_state->peer_htrd, MIO_HTRD_SKIPINITIALLINE | MIO_HTRD_RESPONSE); + mio_htrd_setoption (thr_state->peer_htrd, MIO_HTRD_SKIPINITIALLINE | MIO_HTRD_RESPONSE); mio_htrd_setrecbs (thr_state->peer_htrd, &thr_peer_htrd_recbs); thr_peer = mio_htrd_getxtn(thr_state->peer_htrd); diff --git a/mio/lib/json.c b/mio/lib/json.c index f8a6ca6..9bf09fd 100644 --- a/mio/lib/json.c +++ b/mio/lib/json.c @@ -31,6 +31,9 @@ #define MIO_JSON_TOKEN_NAME_ALIGN 64 +/* this must not overlap with MIO_JSON_INST_XXXX enumerators in mio-json.h */ +#define __INST_WORD_STRING 9999 + /* ========================================================================= */ static void clear_token (mio_json_t* json) @@ -178,7 +181,7 @@ static int invoke_data_inst (mio_json_t* json, mio_json_inst_t inst) /* this is called after the reader has seen a colon. * the data item must be used as a key */ - if (inst != MIO_JSON_INST_STRING) + if (inst != MIO_JSON_INST_STRING && inst != __INST_WORD_STRING) { mio_seterrbfmt (json->mio, MIO_EINVAL, "object key not a string - %.*js", json->tok.len, json->tok.ptr); return -1; @@ -193,6 +196,12 @@ static int invoke_data_inst (mio_json_t* json, mio_json_inst_t inst) } } + if (inst == __INST_WORD_STRING) + { + mio_seterrbfmt (json->mio, MIO_EINVAL, "invalid word value - %.*js", json->tok.len, json->tok.ptr); + return -1; + } + switch (inst) { case MIO_JSON_INST_START_ARRAY: @@ -392,8 +401,12 @@ static int handle_numeric_value_char (mio_json_t* json, mio_ooci_t c) static int handle_word_value_char (mio_json_t* json, mio_ooci_t c) { mio_json_inst_t inst; + int ok; - if (mio_is_ooch_alpha(c)) + ok = (json->option & MIO_JSON_PERMITWORDKEY)? + (mio_is_ooch_alpha(c) || mio_is_ooch_digit(c) || c == '_'): + mio_is_ooch_alpha(c); + if (ok) { if (add_char_to_token(json, c, 0) <= -1) return -1; return 1; @@ -404,6 +417,7 @@ static int handle_word_value_char (mio_json_t* json, mio_ooci_t c) if (mio_comp_oochars_bcstr(json->tok.ptr, json->tok.len, "null", 0) == 0) inst = MIO_JSON_INST_NIL; else if (mio_comp_oochars_bcstr(json->tok.ptr, json->tok.len, "true", 0) == 0) inst = MIO_JSON_INST_TRUE; else if (mio_comp_oochars_bcstr(json->tok.ptr, json->tok.len, "false", 0) == 0) inst = MIO_JSON_INST_FALSE; + else if (json->option & MIO_JSON_PERMITWORDKEY) inst = __INST_WORD_STRING; /* internal only */ else { mio_seterrbfmt (json->mio, MIO_EINVAL, "invalid word value - %.*js", json->tok.len, json->tok.ptr); @@ -801,6 +815,16 @@ void mio_json_fini (mio_json_t* json) } /* ========================================================================= */ +mio_bitmask_t mio_json_getoption (mio_json_t* json) +{ + return json->option; +} + +void mio_json_setoption (mio_json_t* json, mio_bitmask_t mask) +{ + json->option = mask; +} + void mio_json_setinstcb (mio_json_t* json, mio_json_instcb_t instcb, void* ctx) { json->instcb = instcb; diff --git a/mio/lib/mio-htrd.h b/mio/lib/mio-htrd.h index fb5d061..126c4a3 100644 --- a/mio/lib/mio-htrd.h +++ b/mio/lib/mio-htrd.h @@ -52,13 +52,13 @@ typedef enum mio_htrd_errnum_t mio_htrd_errnum_t; */ enum mio_htrd_option_t { - MIO_HTRD_SKIPEMPTYLINES = (1 << 0), /**< skip leading empty lines before the initial line */ - MIO_HTRD_SKIPINITIALLINE = (1 << 1), /**< skip processing an initial line */ - MIO_HTRD_CANONQPATH = (1 << 2), /**< canonicalize the query path */ - MIO_HTRD_REQUEST = (1 << 3), /**< parse input as a request */ - MIO_HTRD_RESPONSE = (1 << 4), /**< parse input as a response */ - MIO_HTRD_TRAILERS = (1 << 5), /**< store trailers in a separate table */ - MIO_HTRD_STRICT = (1 << 6) /**< be more picky */ + MIO_HTRD_SKIPEMPTYLINES = ((mio_bitmask_t)1 << 0), /**< skip leading empty lines before the initial line */ + MIO_HTRD_SKIPINITIALLINE = ((mio_bitmask_t)1 << 1), /**< skip processing an initial line */ + MIO_HTRD_CANONQPATH = ((mio_bitmask_t)1 << 2), /**< canonicalize the query path */ + MIO_HTRD_REQUEST = ((mio_bitmask_t)1 << 3), /**< parse input as a request */ + MIO_HTRD_RESPONSE = ((mio_bitmask_t)1 << 4), /**< parse input as a response */ + MIO_HTRD_TRAILERS = ((mio_bitmask_t)1 << 5), /**< store trailers in a separate table */ + MIO_HTRD_STRICT = ((mio_bitmask_t)1 << 6) /**< be more picky */ }; typedef enum mio_htrd_option_t mio_htrd_option_t; @@ -76,7 +76,7 @@ struct mio_htrd_t { mio_t* mio; mio_htrd_errnum_t errnum; - int option; + mio_bitmask_t option; int flags; mio_htrd_recbs_t recbs; @@ -153,13 +153,13 @@ MIO_EXPORT void mio_htrd_clear ( mio_htrd_t* htrd ); -MIO_EXPORT int mio_htrd_getopt ( +MIO_EXPORT mio_bitmask_t mio_htrd_getoption ( mio_htrd_t* htrd ); -MIO_EXPORT void mio_htrd_setopt ( - mio_htrd_t* htrd, - int opts +MIO_EXPORT void mio_htrd_setoption ( + mio_htrd_t* htrd, + mio_bitmask_t mask ); MIO_EXPORT const mio_htrd_recbs_t* mio_htrd_getrecbs ( diff --git a/mio/lib/mio-json.h b/mio/lib/mio-json.h index 06a2b74..5075de6 100644 --- a/mio/lib/mio-json.h +++ b/mio/lib/mio-json.h @@ -120,16 +120,27 @@ struct mio_json_state_node_t mio_json_state_node_t* next; }; +enum mio_json_option_t +{ + /* allow an unquoted word as an object key */ + MIO_JSON_PERMITWORDKEY = ((mio_bitmask_t)1 << 0), +}; + +typedef enum mio_json_option_t mio_json_option_t; + + struct mio_json_t { mio_t* mio; mio_json_instcb_t instcb; void* rctx; + mio_bitmask_t option; mio_json_state_node_t state_top; mio_json_state_node_t* state_stack; mio_oocs_t tok; mio_oow_t tok_capa; + }; /* ========================================================================= */ @@ -208,6 +219,15 @@ static MIO_INLINE void* mio_json_getxtn (mio_json_t* json) { return (void*)(json #define mio_json_getxtn(json) ((void*)((mio_json_t*)(json) + 1)) #endif +MIO_EXPORT mio_bitmask_t mio_json_getoption ( + mio_json_t* json +); + +MIO_EXPORT void mio_json_setoption ( + mio_json_t* json, + mio_bitmask_t mask +); + MIO_EXPORT void mio_json_setinstcb ( mio_json_t* json, mio_json_instcb_t instcb,