Fossil SCM

fossil-scm / src / json_detail.h
Source Blame History 273 lines
796dcfe… drh 1 #ifdef FOSSIL_ENABLE_JSON
796dcfe… drh 2 #if !defined(FOSSIL_JSON_DETAIL_H_INCLUDED)
796dcfe… drh 3 #define FOSSIL_JSON_DETAIL_H_INCLUDED
796dcfe… drh 4 /*
c19f34c… drh 5 ** Copyright (c) 2011 D. Richard Hipp
796dcfe… drh 6 **
796dcfe… drh 7 ** This program is free software; you can redistribute it and/or
796dcfe… drh 8 ** modify it under the terms of the Simplified BSD License (also
796dcfe… drh 9 ** known as the "2-Clause License" or "FreeBSD License".)
796dcfe… drh 10 **
796dcfe… drh 11 ** This program is distributed in the hope that it will be useful,
796dcfe… drh 12 ** but without any warranty; without even the implied warranty of
796dcfe… drh 13 ** merchantability or fitness for a particular purpose.
796dcfe… drh 14 **
796dcfe… drh 15 ** Author contact information:
796dcfe… drh 16 ** [email protected]
796dcfe… drh 17 ** http://www.hwaci.com/drh/
796dcfe… drh 18 **
796dcfe… drh 19 */
796dcfe… drh 20
2dbc715… mistachkin 21 #if !defined(_RC_COMPILE_)
796dcfe… drh 22 #include "cson_amalgamation.h"
2dbc715… mistachkin 23 #endif /* !defined(_RC_COMPILE_) */
24d830c… stephan 24
24d830c… stephan 25 /**
24d830c… stephan 26 FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
824ede2… stephan 27 "significant" change to the JSON API (a change in an interface or
824ede2… stephan 28 new functionality). It is sent as part of the /json/version
824ede2… stephan 29 request. We could arguably add it to each response or even add a
824ede2… stephan 30 version number to each response type, allowing very fine (too
824ede2… stephan 31 fine?) granularity in compatibility change notification. The
824ede2… stephan 32 version number could be included in part of the command dispatching
824ede2… stephan 33 framework, allowing the top-level dispatching code to deal with it
824ede2… stephan 34 (for the most part).
24d830c… stephan 35 */
824ede2… stephan 36 #define FOSSIL_JSON_API_VERSION "20120713"
24d830c… stephan 37
796dcfe… drh 38 /*
796dcfe… drh 39 ** Impl details for the JSON API which need to be shared
796dcfe… drh 40 ** across multiple C files.
796dcfe… drh 41 */
796dcfe… drh 42
796dcfe… drh 43 /*
796dcfe… drh 44 ** The "official" list of Fossil/JSON error codes. Their values might
796dcfe… drh 45 ** very well change during initial development but after their first
796dcfe… drh 46 ** public release they must stay stable.
796dcfe… drh 47 **
796dcfe… drh 48 ** Values must be in the range 1000..9999 for error codes and 1..999
796dcfe… drh 49 ** for warning codes.
796dcfe… drh 50 **
796dcfe… drh 51 ** Numbers evenly dividable by 100 are "categories", and error codes
796dcfe… drh 52 ** for a given category have their high bits set to the category
796dcfe… drh 53 ** value.
796dcfe… drh 54 **
6ca400a… stephan 55 ** Maintenance reminder: when entries are added to this list, update
6ca400a… stephan 56 ** the code in json_page_resultCodes() and json_err_cstr() (both in
6ca400a… stephan 57 ** json.c)!
6ca400a… stephan 58 **
796dcfe… drh 59 */
2dbc715… mistachkin 60 #if !defined(_RC_COMPILE_)
796dcfe… drh 61 enum FossilJsonCodes {
796dcfe… drh 62 FSL_JSON_W_START = 0,
796dcfe… drh 63 FSL_JSON_W_UNKNOWN /*+1*/,
796dcfe… drh 64 FSL_JSON_W_ROW_TO_JSON_FAILED /*+2*/,
796dcfe… drh 65 FSL_JSON_W_COL_TO_JSON_FAILED /*+3*/,
796dcfe… drh 66 FSL_JSON_W_STRING_TO_ARRAY_FAILED /*+4*/,
796dcfe… drh 67 FSL_JSON_W_TAG_NOT_FOUND /*+5*/,
796dcfe… drh 68
796dcfe… drh 69 FSL_JSON_W_END = 1000,
796dcfe… drh 70 FSL_JSON_E_GENERIC = 1000,
796dcfe… drh 71 FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
796dcfe… drh 72 FSL_JSON_E_INVALID_REQUEST /*+1*/,
796dcfe… drh 73 FSL_JSON_E_UNKNOWN_COMMAND /*+2*/,
796dcfe… drh 74 FSL_JSON_E_UNKNOWN /*+3*/,
796dcfe… drh 75 /*REUSE: +4*/
796dcfe… drh 76 FSL_JSON_E_TIMEOUT /*+5*/,
796dcfe… drh 77 FSL_JSON_E_ASSERT /*+6*/,
796dcfe… drh 78 FSL_JSON_E_ALLOC /*+7*/,
796dcfe… drh 79 FSL_JSON_E_NYI /*+8*/,
796dcfe… drh 80 FSL_JSON_E_PANIC /*+9*/,
796dcfe… drh 81 FSL_JSON_E_MANIFEST_READ_FAILED /*+10*/,
796dcfe… drh 82 FSL_JSON_E_FILE_OPEN_FAILED /*+11*/,
796dcfe… drh 83
796dcfe… drh 84 FSL_JSON_E_AUTH = 2000,
796dcfe… drh 85 FSL_JSON_E_MISSING_AUTH /*+1*/,
796dcfe… drh 86 FSL_JSON_E_DENIED /*+2*/,
796dcfe… drh 87 FSL_JSON_E_WRONG_MODE /*+3*/,
796dcfe… drh 88
796dcfe… drh 89 FSL_JSON_E_LOGIN_FAILED = FSL_JSON_E_AUTH +100,
796dcfe… drh 90 FSL_JSON_E_LOGIN_FAILED_NOSEED /*+1*/,
796dcfe… drh 91 FSL_JSON_E_LOGIN_FAILED_NONAME /*+2*/,
796dcfe… drh 92 FSL_JSON_E_LOGIN_FAILED_NOPW /*+3*/,
796dcfe… drh 93 FSL_JSON_E_LOGIN_FAILED_NOTFOUND /*+4*/,
796dcfe… drh 94
796dcfe… drh 95 FSL_JSON_E_USAGE = 3000,
796dcfe… drh 96 FSL_JSON_E_INVALID_ARGS /*+1*/,
796dcfe… drh 97 FSL_JSON_E_MISSING_ARGS /*+2*/,
796dcfe… drh 98 FSL_JSON_E_AMBIGUOUS_UUID /*+3*/,
796dcfe… drh 99 FSL_JSON_E_UNRESOLVED_UUID /*+4*/,
796dcfe… drh 100 FSL_JSON_E_RESOURCE_ALREADY_EXISTS /*+5*/,
796dcfe… drh 101 FSL_JSON_E_RESOURCE_NOT_FOUND /*+6*/,
796dcfe… drh 102
796dcfe… drh 103 FSL_JSON_E_DB = 4000,
796dcfe… drh 104 FSL_JSON_E_STMT_PREP /*+1*/,
796dcfe… drh 105 FSL_JSON_E_STMT_BIND /*+2*/,
796dcfe… drh 106 FSL_JSON_E_STMT_EXEC /*+3*/,
796dcfe… drh 107 FSL_JSON_E_DB_LOCKED /*+4*/,
796dcfe… drh 108
796dcfe… drh 109 FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101,
796dcfe… drh 110 FSL_JSON_E_DB_NOT_FOUND = FSL_JSON_E_DB + 102,
d1e4d10… stephan 111 FSL_JSON_E_DB_NOT_VALID = FSL_JSON_E_DB + 103,
d1e4d10… stephan 112 /*
d1e4d10… stephan 113 ** Maintenance reminder: FSL_JSON_E_DB_NOT_FOUND gets triggered in the
d1e4d10… stephan 114 ** bootstrapping process before we know whether we need to check for
d1e4d10… stephan 115 ** FSL_JSON_E_DB_NEEDS_CHECKOUT. Thus the former error trumps the
d1e4d10… stephan 116 ** latter.
d1e4d10… stephan 117 */
d1e4d10… stephan 118 FSL_JSON_E_DB_NEEDS_CHECKOUT = FSL_JSON_E_DB + 104
796dcfe… drh 119 };
796dcfe… drh 120
796dcfe… drh 121
796dcfe… drh 122 /*
796dcfe… drh 123 ** Signature for JSON page/command callbacks. Each callback is
796dcfe… drh 124 ** responsible for handling one JSON request/command and/or
796dcfe… drh 125 ** dispatching to sub-commands.
796dcfe… drh 126 **
796dcfe… drh 127 ** By the time the callback is called, json_page_top() (HTTP mode) or
796dcfe… drh 128 ** json_cmd_top() (CLI mode) will have set up the JSON-related
796dcfe… drh 129 ** environment. Implementations may generate a "result payload" of any
796dcfe… drh 130 ** JSON type by returning its value from this function (ownership is
db0c512… drh 131 ** transferred to the caller). On error they should set
796dcfe… drh 132 ** g.json.resultCode to one of the FossilJsonCodes values and return
796dcfe… drh 133 ** either their payload object or NULL. Note that NULL is a legal
796dcfe… drh 134 ** success value - it simply means the response will contain no
796dcfe… drh 135 ** payload. If g.json.resultCode is non-zero when this function
796dcfe… drh 136 ** returns then the top-level dispatcher will destroy any payload
796dcfe… drh 137 ** returned by this function and will output a JSON error response
796dcfe… drh 138 ** instead.
796dcfe… drh 139 **
796dcfe… drh 140 ** All of the setup/response code is handled by the top dispatcher
796dcfe… drh 141 ** functions and the callbacks concern themselves only with:
796dcfe… drh 142 **
796dcfe… drh 143 ** a) Permissions checking (inspecting g.perm).
796dcfe… drh 144 ** b) generating a response payload (if applicable)
796dcfe… drh 145 ** c) Setting g.json's error state (if applicable). See json_set_err().
796dcfe… drh 146 **
db0c512… drh 147 ** It is imperative that NO callback functions EVER output ANYTHING to
796dcfe… drh 148 ** stdout, as that will effectively corrupt any JSON output, and
796dcfe… drh 149 ** almost certainly will corrupt any HTTP response headers. Output
796dcfe… drh 150 ** sent to stderr ends up in my apache log, so that might be useful
db0c512… drh 151 ** for debugging in some cases, but no such code should be left
db0c512… drh 152 ** enabled for non-debugging builds.
796dcfe… drh 153 */
a80f274… stephan 154 typedef cson_value * (*fossil_json_f)(void);
796dcfe… drh 155
796dcfe… drh 156 /*
796dcfe… drh 157 ** Holds name-to-function mappings for JSON page/command dispatching.
796dcfe… drh 158 **
796dcfe… drh 159 ** Internally we model page dispatching lists as arrays of these
796dcfe… drh 160 ** objects, where the final entry in the array has a NULL name value
796dcfe… drh 161 ** to act as the end-of-list sentinel.
796dcfe… drh 162 **
796dcfe… drh 163 */
796dcfe… drh 164 typedef struct JsonPageDef{
796dcfe… drh 165 /*
796dcfe… drh 166 ** The commmand/page's name (path, not including leading /json/).
796dcfe… drh 167 **
796dcfe… drh 168 ** Reminder to self: we cannot use sub-paths with commands this way
796dcfe… drh 169 ** without additional string-splitting downstream. e.g. foo/bar.
796dcfe… drh 170 ** Alternately, we can create different JsonPageDef arrays for each
796dcfe… drh 171 ** subset.
796dcfe… drh 172 */
796dcfe… drh 173 char const * name;
796dcfe… drh 174 /*
796dcfe… drh 175 ** Returns a payload object for the response. If it returns a
796dcfe… drh 176 ** non-NULL value, the caller owns it. To trigger an error this
796dcfe… drh 177 ** function should set g.json.resultCode to a value from the
796dcfe… drh 178 ** FossilJsonCodes enum. If it sets an error value and returns
796dcfe… drh 179 ** a payload, the payload will be destroyed (not sent with the
796dcfe… drh 180 ** response).
796dcfe… drh 181 */
796dcfe… drh 182 fossil_json_f func;
796dcfe… drh 183 /*
796dcfe… drh 184 ** Which mode(s) of execution does func() support:
796dcfe… drh 185 **
796dcfe… drh 186 ** <0 = CLI only, >0 = HTTP only, 0==both
0c234bd… stephan 187 **
0c234bd… stephan 188 ** Now that we can simulate POST in CLI mode, the distinction
db0c512… drh 189 ** between them has disappeared in most (or all) cases, so 0 is
0c234bd… stephan 190 ** the standard value.
796dcfe… drh 191 */
8f6b78e… stephan 192 int runMode;
796dcfe… drh 193 } JsonPageDef;
796dcfe… drh 194
796dcfe… drh 195 /*
796dcfe… drh 196 ** Holds common keys used for various JSON API properties.
796dcfe… drh 197 */
796dcfe… drh 198 typedef struct FossilJsonKeys_{
796dcfe… drh 199 /** maintainers: please keep alpha sorted (case-insensitive) */
796dcfe… drh 200 char const * anonymousSeed;
796dcfe… drh 201 char const * authToken;
796dcfe… drh 202 char const * commandPath;
796dcfe… drh 203 char const * mtime;
796dcfe… drh 204 char const * payload;
796dcfe… drh 205 char const * requestId;
796dcfe… drh 206 char const * resultCode;
796dcfe… drh 207 char const * resultText;
796dcfe… drh 208 char const * timestamp;
796dcfe… drh 209 } FossilJsonKeys_;
ba86c85… stephan 210 extern const FossilJsonKeys_ FossilJsonKeys;
796dcfe… drh 211
796dcfe… drh 212 /*
796dcfe… drh 213 ** A page/command dispatch helper for fossil_json_f() implementations.
796dcfe… drh 214 ** pages must be an array of JsonPageDef commands which we can
796dcfe… drh 215 ** dispatch. The final item in the array MUST have a NULL name
796dcfe… drh 216 ** element.
796dcfe… drh 217 **
796dcfe… drh 218 ** This function takes the command specified in
db0c512… drh 219 ** json_command_arg(1+g.json.dispatchDepth) and searches pages for a
796dcfe… drh 220 ** matching name. If found then that page's func() is called to fetch
796dcfe… drh 221 ** the payload, which is returned to the caller.
796dcfe… drh 222 **
796dcfe… drh 223 ** On error, g.json.resultCode is set to one of the FossilJsonCodes
796dcfe… drh 224 ** values and NULL is returned. If non-NULL is returned, ownership is
796dcfe… drh 225 ** transfered to the caller (but the g.json error state might still be
796dcfe… drh 226 ** set in that case, so the caller must check that or pass it on up
796dcfe… drh 227 ** the dispatch chain).
796dcfe… drh 228 */
796dcfe… drh 229 cson_value * json_page_dispatch_helper(JsonPageDef const * pages);
796dcfe… drh 230
796dcfe… drh 231 /*
796dcfe… drh 232 ** Convenience wrapper around cson_value_new_string().
796dcfe… drh 233 ** Returns NULL if str is NULL or on allocation error.
796dcfe… drh 234 */
796dcfe… drh 235 cson_value * json_new_string( char const * str );
796dcfe… drh 236
796dcfe… drh 237 /*
796dcfe… drh 238 ** Similar to json_new_string(), but takes a printf()-style format
796dcfe… drh 239 ** specifiers. Supports the printf extensions supported by fossil's
796dcfe… drh 240 ** mprintf(). Returns NULL if str is NULL or on allocation error.
796dcfe… drh 241 **
796dcfe… drh 242 ** Maintenance note: json_new_string() is NOT variadic because by the
796dcfe… drh 243 ** time the variadic form was introduced we already had use cases
796dcfe… drh 244 ** which segfaulted via json_new_string() because they contain printf
796dcfe… drh 245 ** markup (e.g. wiki content). Been there, debugged that.
796dcfe… drh 246 */
796dcfe… drh 247 cson_value * json_new_string_f( char const * fmt, ... );
796dcfe… drh 248
796dcfe… drh 249 /*
796dcfe… drh 250 ** Returns true if fossil is running in JSON mode and we are either
796dcfe… drh 251 ** running in HTTP mode OR g.json.post.o is not NULL (meaning POST
796dcfe… drh 252 ** data was fed in from CLI mode).
796dcfe… drh 253 **
796dcfe… drh 254 ** Specifically, it will return false when any of these apply:
796dcfe… drh 255 **
796dcfe… drh 256 ** a) Not running in JSON mode (via json command or /json path).
796dcfe… drh 257 **
796dcfe… drh 258 ** b) We are running in JSON CLI mode, but no POST data has been fed
796dcfe… drh 259 ** in.
796dcfe… drh 260 **
796dcfe… drh 261 ** Whether or not we need to take args from CLI or POST data makes a
db0c512… drh 262 ** difference in argument/parameter handling in many JSON routines,
796dcfe… drh 263 ** and thus this distinction.
796dcfe… drh 264 */
a80f274… stephan 265 int fossil_has_json(void);
824ede2… stephan 266
824ede2… stephan 267 enum json_get_changed_files_flags {
824ede2… stephan 268 json_get_changed_files_ELIDE_PARENT = 1 << 0
824ede2… stephan 269 };
796dcfe… drh 270
2dbc715… mistachkin 271 #endif /* !defined(_RC_COMPILE_) */
796dcfe… drh 272 #endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
796dcfe… drh 273 #endif /* FOSSIL_ENABLE_JSON */

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button