diff options
Diffstat (limited to 'src/json_detail.h')
| -rw-r--r-- | src/json_detail.h | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/json_detail.h b/src/json_detail.h new file mode 100644 index 0000000..8828bb1 --- /dev/null +++ b/src/json_detail.h @@ -0,0 +1,273 @@ +#ifdef FOSSIL_ENABLE_JSON +#if !defined(FOSSIL_JSON_DETAIL_H_INCLUDED) +#define FOSSIL_JSON_DETAIL_H_INCLUDED +/* +** Copyright (c) 2011 D. Richard Hipp +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the Simplified BSD License (also +** known as the "2-Clause License" or "FreeBSD License".) +** +** This program is distributed in the hope that it will be useful, +** but without any warranty; without even the implied warranty of +** merchantability or fitness for a particular purpose. +** +** Author contact information: +** drh@hwaci.com +** http://www.hwaci.com/drh/ +** +*/ + +#if !defined(_RC_COMPILE_) +#include "cson_amalgamation.h" +#endif /* !defined(_RC_COMPILE_) */ + +/** + FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest + "significant" change to the JSON API (a change in an interface or + new functionality). It is sent as part of the /json/version + request. We could arguably add it to each response or even add a + version number to each response type, allowing very fine (too + fine?) granularity in compatibility change notification. The + version number could be included in part of the command dispatching + framework, allowing the top-level dispatching code to deal with it + (for the most part). +*/ +#define FOSSIL_JSON_API_VERSION "20120713" + +/* +** Impl details for the JSON API which need to be shared +** across multiple C files. +*/ + +/* +** The "official" list of Fossil/JSON error codes. Their values might +** very well change during initial development but after their first +** public release they must stay stable. +** +** Values must be in the range 1000..9999 for error codes and 1..999 +** for warning codes. +** +** Numbers evenly dividable by 100 are "categories", and error codes +** for a given category have their high bits set to the category +** value. +** +** Maintenance reminder: when entries are added to this list, update +** the code in json_page_resultCodes() and json_err_cstr() (both in +** json.c)! +** +*/ +#if !defined(_RC_COMPILE_) +enum FossilJsonCodes { +FSL_JSON_W_START = 0, +FSL_JSON_W_UNKNOWN /*+1*/, +FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/, +FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/, +FSL_JSON_W_STRING_TO_ARRAY_FAILED /*+4*/, +FSL_JSON_W_TAG_NOT_FOUND /*+5*/, + +FSL_JSON_W_END = 1000, +FSL_JSON_E_GENERIC = 1000, +FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100, +FSL_JSON_E_INVALID_REQUEST /*+1*/, +FSL_JSON_E_UNKNOWN_COMMAND /*+2*/, +FSL_JSON_E_UNKNOWN /*+3*/, +/*REUSE: +4*/ +FSL_JSON_E_TIMEOUT /*+5*/, +FSL_JSON_E_ASSERT /*+6*/, +FSL_JSON_E_ALLOC /*+7*/, +FSL_JSON_E_NYI /*+8*/, +FSL_JSON_E_PANIC /*+9*/, +FSL_JSON_E_MANIFEST_READ_FAILED /*+10*/, +FSL_JSON_E_FILE_OPEN_FAILED /*+11*/, + +FSL_JSON_E_AUTH = 2000, +FSL_JSON_E_MISSING_AUTH /*+1*/, +FSL_JSON_E_DENIED /*+2*/, +FSL_JSON_E_WRONG_MODE /*+3*/, + +FSL_JSON_E_LOGIN_FAILED = FSL_JSON_E_AUTH +100, +FSL_JSON_E_LOGIN_FAILED_NOSEED /*+1*/, +FSL_JSON_E_LOGIN_FAILED_NONAME /*+2*/, +FSL_JSON_E_LOGIN_FAILED_NOPW /*+3*/, +FSL_JSON_E_LOGIN_FAILED_NOTFOUND /*+4*/, + +FSL_JSON_E_USAGE = 3000, +FSL_JSON_E_INVALID_ARGS /*+1*/, +FSL_JSON_E_MISSING_ARGS /*+2*/, +FSL_JSON_E_AMBIGUOUS_UUID /*+3*/, +FSL_JSON_E_UNRESOLVED_UUID /*+4*/, +FSL_JSON_E_RESOURCE_ALREADY_EXISTS /*+5*/, +FSL_JSON_E_RESOURCE_NOT_FOUND /*+6*/, + +FSL_JSON_E_DB = 4000, +FSL_JSON_E_STMT_PREP /*+1*/, +FSL_JSON_E_STMT_BIND /*+2*/, +FSL_JSON_E_STMT_EXEC /*+3*/, +FSL_JSON_E_DB_LOCKED /*+4*/, + +FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101, +FSL_JSON_E_DB_NOT_FOUND = FSL_JSON_E_DB + 102, +FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103, +/* +** Maintenance reminder: FSL_JSON_E_DB_NOT_FOUND gets triggered in the +** bootstrapping process before we know whether we need to check for +** FSL_JSON_E_DB_NEEDS_CHECKOUT. Thus the former error trumps the +** latter. +*/ +FSL_JSON_E_DB_NEEDS_CHECKOUT = FSL_JSON_E_DB + 104 +}; + + +/* +** Signature for JSON page/command callbacks. Each callback is +** responsible for handling one JSON request/command and/or +** dispatching to sub-commands. +** +** By the time the callback is called, json_page_top() (HTTP mode) or +** json_cmd_top() (CLI mode) will have set up the JSON-related +** environment. Implementations may generate a "result payload" of any +** JSON type by returning its value from this function (ownership is +** transferred to the caller). On error they should set +** g.json.resultCode to one of the FossilJsonCodes values and return +** either their payload object or NULL. Note that NULL is a legal +** success value - it simply means the response will contain no +** payload. If g.json.resultCode is non-zero when this function +** returns then the top-level dispatcher will destroy any payload +** returned by this function and will output a JSON error response +** instead. +** +** All of the setup/response code is handled by the top dispatcher +** functions and the callbacks concern themselves only with: +** +** a) Permissions checking (inspecting g.perm). +** b) generating a response payload (if applicable) +** c) Setting g.json's error state (if applicable). See json_set_err(). +** +** It is imperative that NO callback functions EVER output ANYTHING to +** stdout, as that will effectively corrupt any JSON output, and +** almost certainly will corrupt any HTTP response headers. Output +** sent to stderr ends up in my apache log, so that might be useful +** for debugging in some cases, but no such code should be left +** enabled for non-debugging builds. +*/ +typedef cson_value * (*fossil_json_f)(void); + +/* +** Holds name-to-function mappings for JSON page/command dispatching. +** +** Internally we model page dispatching lists as arrays of these +** objects, where the final entry in the array has a NULL name value +** to act as the end-of-list sentinel. +** +*/ +typedef struct JsonPageDef{ + /* + ** The commmand/page's name (path, not including leading /json/). + ** + ** Reminder to self: we cannot use sub-paths with commands this way + ** without additional string-splitting downstream. e.g. foo/bar. + ** Alternately, we can create different JsonPageDef arrays for each + ** subset. + */ + char const * name; + /* + ** Returns a payload object for the response. If it returns a + ** non-NULL value, the caller owns it. To trigger an error this + ** function should set g.json.resultCode to a value from the + ** FossilJsonCodes enum. If it sets an error value and returns + ** a payload, the payload will be destroyed (not sent with the + ** response). + */ + fossil_json_f func; + /* + ** Which mode(s) of execution does func() support: + ** + ** <0 = CLI only, >0 = HTTP only, 0==both + ** + ** Now that we can simulate POST in CLI mode, the distinction + ** between them has disappeared in most (or all) cases, so 0 is + ** the standard value. + */ + int runMode; +} JsonPageDef; + +/* +** Holds common keys used for various JSON API properties. +*/ +typedef struct FossilJsonKeys_{ + /** maintainers: please keep alpha sorted (case-insensitive) */ + char const * anonymousSeed; + char const * authToken; + char const * commandPath; + char const * mtime; + char const * payload; + char const * requestId; + char const * resultCode; + char const * resultText; + char const * timestamp; +} FossilJsonKeys_; +extern const FossilJsonKeys_ FossilJsonKeys; + +/* +** A page/command dispatch helper for fossil_json_f() implementations. +** pages must be an array of JsonPageDef commands which we can +** dispatch. The final item in the array MUST have a NULL name +** element. +** +** This function takes the command specified in +** json_command_arg(1+g.json.dispatchDepth) and searches pages for a +** matching name. If found then that page's func() is called to fetch +** the payload, which is returned to the caller. +** +** On error, g.json.resultCode is set to one of the FossilJsonCodes +** values and NULL is returned. If non-NULL is returned, ownership is +** transfered to the caller (but the g.json error state might still be +** set in that case, so the caller must check that or pass it on up +** the dispatch chain). +*/ +cson_value * json_page_dispatch_helper(JsonPageDef const * pages); + +/* +** Convenience wrapper around cson_value_new_string(). +** Returns NULL if str is NULL or on allocation error. +*/ +cson_value * json_new_string( char const * str ); + +/* +** Similar to json_new_string(), but takes a printf()-style format +** specifiers. Supports the printf extensions supported by fossil's +** mprintf(). Returns NULL if str is NULL or on allocation error. +** +** Maintenance note: json_new_string() is NOT variadic because by the +** time the variadic form was introduced we already had use cases +** which segfaulted via json_new_string() because they contain printf +** markup (e.g. wiki content). Been there, debugged that. +*/ +cson_value * json_new_string_f( char const * fmt, ... ); + +/* +** Returns true if fossil is running in JSON mode and we are either +** running in HTTP mode OR g.json.post.o is not NULL (meaning POST +** data was fed in from CLI mode). +** +** Specifically, it will return false when any of these apply: +** +** a) Not running in JSON mode (via json command or /json path). +** +** b) We are running in JSON CLI mode, but no POST data has been fed +** in. +** +** Whether or not we need to take args from CLI or POST data makes a +** difference in argument/parameter handling in many JSON routines, +** and thus this distinction. +*/ +int fossil_has_json(void); + +enum json_get_changed_files_flags { + json_get_changed_files_ELIDE_PARENT = 1 << 0 +}; + +#endif /* !defined(_RC_COMPILE_) */ +#endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/ +#endif /* FOSSIL_ENABLE_JSON */ |
