1 #ifdef FOSSIL_ENABLE_JSON
2 /*
3 ** Copyright (c) 2011 D. Richard Hipp
4 **
5 ** This program is free software; you can redistribute it and/or
6 ** modify it under the terms of the Simplified BSD License (also
7 ** known as the "2-Clause License" or "FreeBSD License".)
8 
9 ** This program is distributed in the hope that it will be useful,
10 ** but without any warranty; without even the implied warranty of
11 ** merchantability or fitness for a particular purpose.
12 **
13 ** Author contact information:
14 **   drh@hwaci.com
15 **   http://www.hwaci.com/drh/
16 **
17 *******************************************************************************
18 **
19 ** Code for the JSON API.
20 **
21 ** The JSON API's public interface is documented at:
22 **
23 ** https://fossil-scm.org/fossil/doc/trunk/www/json-api/index.md
24 **
25 ** Notes for hackers...
26 **
27 ** Here's how command/page dispatching works: json_page_top() (in HTTP mode) or
28 ** json_cmd_top() (in CLI mode) catch the "json" path/command. Those functions then
29 ** dispatch to a JSON-mode-specific command/page handler with the type fossil_json_f().
30 ** See the API docs for that typedef (below) for the semantics of the callbacks.
31 **
32 **
33 */
34 #include "VERSION.h"
35 #include "config.h"
36 #include "json.h"
37 #include <assert.h>
38 #include <time.h>
39 
40 #if INTERFACE
41 #include "json_detail.h" /* workaround for apparent enum limitation in makeheaders */
42 #endif
43 
44 const FossilJsonKeys_ FossilJsonKeys = {
45   "anonymousSeed" /*anonymousSeed*/,
46   "authToken"  /*authToken*/,
47   "COMMAND_PATH" /*commandPath*/,
48   "mtime" /*mtime*/,
49   "payload" /* payload */,
50   "requestId" /*requestId*/,
51   "resultCode" /*resultCode*/,
52   "resultText" /*resultText*/,
53   "timestamp" /*timestamp*/
54 };
55 
56 /*
57 ** Given the current request path string, this function returns true
58 ** if it refers to a JSON API path. i.e. if (1) it starts with /json
59 ** or (2) g.zCmdName is "server" or "cgi" and the path starts with
60 ** /somereponame/json. Specifically, it returns 1 in the former case
61 ** and 2 for the latter.
62 */
json_request_is_json_api(const char * zPathInfo)63 int json_request_is_json_api(const char * zPathInfo){
64   int rc = 0;
65   if(zPathInfo==0){
66     rc = 0;
67   }else if(0==strncmp("/json",zPathInfo,5)
68            && (zPathInfo[5]==0 || zPathInfo[5]=='/')){
69     rc = 1;
70   }else if(g.zCmdName!=0 && (0==strcmp("server",g.zCmdName)
71                              || 0==strcmp("ui",g.zCmdName)
72                              || 0==strcmp("cgi",g.zCmdName)
73                              || 0==strcmp("http",g.zCmdName)) ){
74     /* When running in server/cgi "directory" mode, zPathInfo is
75     ** prefixed with the repository's name, so in order to determine
76     ** whether or not we're really running in json mode we have to try
77     ** a bit harder. Problem reported here:
78     ** https://fossil-scm.org/forum/forumpost/e4953666d6
79     */
80     ReCompiled * pReg = 0;
81     const char * zErr = re_compile(&pReg, "^/[^/]+/json(/.*)?", 0);
82     assert(zErr==0 && "Regex compilation failed?");
83     if(zErr==0 &&
84          re_match(pReg, (const unsigned char *)zPathInfo, -1)){
85       rc = 2;
86     }
87     re_free(pReg);
88   }
89   return rc;
90 }
91 
92 /*
93 ** Returns true (non-0) if fossil appears to be running in JSON mode.
94 ** and either has JSON POSTed input awaiting consumption or fossil is
95 ** running in HTTP mode (in which case certain JSON data *might* be
96 ** available via GET parameters).
97 */
fossil_has_json()98 int fossil_has_json(){
99   return g.json.isJsonMode && (g.isHTTP || g.json.post.o);
100 }
101 
102 /*
103 ** Placeholder /json/XXX page impl for NYI (Not Yet Implemented)
104 ** (but planned) pages/commands.
105 */
json_page_nyi()106 cson_value * json_page_nyi(){
107   g.json.resultCode = FSL_JSON_E_NYI;
108   return NULL;
109 }
110 
111 /*
112 ** Given a FossilJsonCodes value, it returns a string suitable for use
113 ** as a resultCode string. Returns some unspecified non-empty string
114 ** if errCode is not one of the FossilJsonCodes values.
115 */
json_err_cstr(int errCode)116 static char const * json_err_cstr( int errCode ){
117   switch( errCode ){
118     case 0: return "Success";
119 #define C(X,V) case FSL_JSON_E_ ## X: return V
120 
121     C(GENERIC,"Generic error");
122     C(INVALID_REQUEST,"Invalid request");
123     C(UNKNOWN_COMMAND,"Unknown command or subcommand");
124     C(UNKNOWN,"Unknown error");
125     C(TIMEOUT,"Timeout reached");
126     C(ASSERT,"Assertion failed");
127     C(ALLOC,"Resource allocation failed");
128     C(NYI,"Not yet implemented");
129     C(PANIC,"x");
130     C(MANIFEST_READ_FAILED,"Reading artifact manifest failed");
131     C(FILE_OPEN_FAILED,"Opening file failed");
132 
133     C(AUTH,"Authentication error");
134     C(MISSING_AUTH,"Authentication info missing from request");
135     C(DENIED,"Access denied");
136     C(WRONG_MODE,"Request not allowed (wrong operation mode)");
137     C(LOGIN_FAILED,"Login failed");
138     C(LOGIN_FAILED_NOSEED,"Anonymous login attempt was missing password seed");
139     C(LOGIN_FAILED_NONAME,"Login failed - name not supplied");
140     C(LOGIN_FAILED_NOPW,"Login failed - password not supplied");
141     C(LOGIN_FAILED_NOTFOUND,"Login failed - no match found");
142 
143     C(USAGE,"Usage error");
144     C(INVALID_ARGS,"Invalid argument(s)");
145     C(MISSING_ARGS,"Missing argument(s)");
146     C(AMBIGUOUS_UUID,"Resource identifier is ambiguous");
147     C(UNRESOLVED_UUID,"Provided uuid/tag/branch could not be resolved");
148     C(RESOURCE_ALREADY_EXISTS,"Resource already exists");
149     C(RESOURCE_NOT_FOUND,"Resource not found");
150 
151     C(DB,"Database error");
152     C(STMT_PREP,"Statement preparation failed");
153     C(STMT_BIND,"Statement parameter binding failed");
154     C(STMT_EXEC,"Statement execution/stepping failed");
155     C(DB_LOCKED,"Database is locked");
156     C(DB_NEEDS_REBUILD,"Fossil repository needs to be rebuilt");
157     C(DB_NOT_FOUND,"Fossil repository db file could not be found.");
158     C(DB_NOT_VALID, "Fossil repository db file is not valid.");
159     C(DB_NEEDS_CHECKOUT, "Command requires a local checkout.");
160 #undef C
161     default:
162       return "Unknown Error";
163   }
164 }
165 
166 /*
167 ** Implements the cson_data_dest_f() interface and outputs the data to
168 ** a fossil Blob object.  pState must be-a initialized (Blob*), to
169 ** which n bytes of src will be appended.
170 **/
cson_data_dest_Blob(void * pState,void const * src,unsigned int n)171 int cson_data_dest_Blob(void * pState, void const * src, unsigned int n){
172   Blob * b = (Blob*)pState;
173   blob_append( b, (char const *)src, (int)n ) /* will die on OOM */;
174   return 0;
175 }
176 
177 /*
178 ** Implements the cson_data_source_f() interface and reads input from
179 ** a fossil Blob object. pState must be-a (Blob*) populated with JSON
180 ** data.
181 */
cson_data_src_Blob(void * pState,void * dest,unsigned int * n)182 int cson_data_src_Blob(void * pState, void * dest, unsigned int * n){
183   Blob * b = (Blob*)pState;
184   *n = blob_read( b, dest, *n );
185   return 0;
186 }
187 
188 /*
189 ** Convenience wrapper around cson_output() which appends the output
190 ** to pDest. pOpt may be NULL, in which case g.json.outOpt will be used.
191 */
cson_output_Blob(cson_value const * pVal,Blob * pDest,cson_output_opt const * pOpt)192 int cson_output_Blob( cson_value const * pVal, Blob * pDest, cson_output_opt const * pOpt ){
193   return cson_output( pVal, cson_data_dest_Blob,
194                       pDest, pOpt ? pOpt : &g.json.outOpt );
195 }
196 
197 /*
198 ** Convenience wrapper around cson_parse() which reads its input
199 ** from pSrc. pSrc is rewound before parsing.
200 **
201 ** pInfo may be NULL. If it is not NULL then it will contain details
202 ** about the parse state when this function returns.
203 **
204 ** On success a new JSON Object or Array is returned (owned by the
205 ** caller). On error NULL is returned.
206 */
cson_parse_Blob(Blob * pSrc,cson_parse_info * pInfo)207 cson_value * cson_parse_Blob( Blob * pSrc, cson_parse_info * pInfo ){
208   cson_value * root = NULL;
209   blob_rewind( pSrc );
210   cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo );
211   return root;
212 }
213 
214 /*
215 ** Implements the cson_data_dest_f() interface and outputs the data to
216 ** cgi_append_content(). pState is ignored.
217 **/
cson_data_dest_cgi(void * pState,void const * src,unsigned int n)218 int cson_data_dest_cgi(void * pState, void const * src, unsigned int n){
219   cgi_append_content( (char const *)src, (int)n );
220   return 0;
221 }
222 
223 /*
224 ** Returns a string in the form FOSSIL-XXXX, where XXXX is a
225 ** left-zero-padded value of code. The returned buffer is static, and
226 ** must be copied if needed for later.  The returned value will always
227 ** be 11 bytes long (not including the trailing NUL byte).
228 **
229 ** In practice we will only ever call this one time per app execution
230 ** when constructing the JSON response envelope, so the static buffer
231 ** "shouldn't" be a problem.
232 **
233 */
json_rc_cstr(int code)234 char const * json_rc_cstr( int code ){
235   enum { BufSize = 12 };
236   static char buf[BufSize] = {'F','O','S','S','I','L','-',0};
237   assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
238   sprintf(buf+7,"%04d", code);
239   return buf;
240 }
241 
242 /*
243 ** Adds v to the API-internal cleanup mechanism. key is ignored
244 ** (legacy) but might be re-introduced and "should" be a unique
245 ** (app-wide) value.  Failure to insert an item may be caused by any
246 ** of the following:
247 **
248 ** - Allocation error.
249 ** - g.json.gc.a is NULL
250 ** - key is NULL or empty.
251 **
252 ** Returns 0 on success.
253 **
254 ** Ownership of v is transfered to (or shared with) g.json.gc, and v
255 ** will be valid until that object is cleaned up or some internal code
256 ** incorrectly removes it from the gc (which we never do). If this
257 ** function fails, it is fatal to the app (as it indicates an
258 ** allocation error (more likely than not) or a serious internal error
259 ** such as numeric overflow).
260 */
json_gc_add(char const * key,cson_value * v)261 void json_gc_add( char const * key, cson_value * v ){
262   int const rc = cson_array_append( g.json.gc.a, v );
263 
264   assert( NULL != g.json.gc.a );
265   if( 0 != rc ){
266     cson_value_free( v );
267   }
268   assert( (0==rc) && "Adding item to GC failed." );
269   if(0!=rc){
270     fprintf(stderr,"%s: FATAL: alloc error.\n", g.argv[0])
271         /* reminder: allocation error is the only reasonable cause of
272            error here, provided g.json.gc.a and v are not NULL.
273         */
274         ;
275     fossil_exit(1)/*not fossil_panic() b/c it might land us somewhere
276                     where this function is called again.
277                   */;
278   }
279 }
280 
281 
282 /*
283 ** Returns the value of json_rc_cstr(code) as a new JSON
284 ** string, which is owned by the caller and must eventually
285 ** be cson_value_free()d or transfered to a JSON container.
286 */
json_rc_string(int code)287 cson_value * json_rc_string( int code ){
288   return cson_value_new_string( json_rc_cstr(code), 11 );
289 }
290 
json_new_string(char const * str)291 cson_value * json_new_string( char const * str ){
292   return str
293     ? cson_value_new_string(str,strlen(str))
294     : NULL;
295 }
296 
json_new_string_f(char const * fmt,...)297 cson_value * json_new_string_f( char const * fmt, ... ){
298   cson_value * v;
299   char * zStr;
300   va_list vargs;
301   va_start(vargs,fmt);
302   zStr = vmprintf(fmt,vargs);
303   va_end(vargs);
304   v = cson_value_new_string(zStr, strlen(zStr));
305   free(zStr);
306   return v;
307 }
308 
json_new_int(i64 v)309 cson_value * json_new_int( i64 v ){
310   return cson_value_new_integer((cson_int_t)v);
311 }
312 
313 /*
314 ** Gets a POST/POST.payload/GET/COOKIE/ENV value. The returned memory
315 ** is owned by the g.json object (one of its sub-objects). Returns
316 ** NULL if no match is found.
317 **
318 ** ENV means the system environment (getenv()).
319 **
320 ** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV.
321 **
322 ** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE,
323 ** ENV, but the amalgamation of the GET/POST vars makes it effectively
324 ** impossible to do that. Since fossil only uses one cookie, cookie
325 ** precedence isn't a real/high-priority problem.
326 */
json_getenv(char const * zKey)327 cson_value * json_getenv( char const * zKey ){
328   cson_value * rc;
329   rc = g.json.reqPayload.o
330     ? cson_object_get( g.json.reqPayload.o, zKey )
331     : NULL;
332   if(rc){
333     return rc;
334   }
335   rc = cson_object_get( g.json.param.o, zKey );
336   if( rc ){
337     return rc;
338   }
339   rc = cson_object_get( g.json.post.o, zKey );
340   if(rc){
341     return rc;
342   }else{
343     char const * cv = PD(zKey,NULL);
344     if(!cv && !g.isHTTP){
345       /* reminder to self: in CLI mode i'd like to try
346          find_option(zKey,NULL,XYZ) here, but we don't have a sane
347          default for the XYZ param here.
348       */
349       cv = fossil_getenv(zKey);
350     }
351     if(cv){/*transform it to JSON for later use.*/
352       /* use sscanf() to figure out if it's an int,
353          and transform it to JSON int if it is.
354 
355          FIXME: use strtol(), since it has more accurate
356          error handling.
357       */
358       int intVal = -1;
359       char endOfIntCheck;
360       int const scanRc = sscanf(cv,"%d%c",&intVal, &endOfIntCheck)
361         /* The %c bit there is to make sure that we don't accept 123x
362           as a number. sscanf() returns the number of tokens
363           successfully parsed, so an RC of 1 will be correct for "123"
364           but "123x" will have RC==2.
365 
366           But it appears to not be working that way :/
367         */
368         ;
369       if(1==scanRc){
370         json_setenv( zKey, cson_value_new_integer(intVal) );
371       }else{
372         rc = cson_value_new_string(cv,strlen(cv));
373         json_setenv( zKey, rc );
374       }
375       return rc;
376     }else{
377       return NULL;
378     }
379   }
380 }
381 
382 /*
383 ** Wrapper around json_getenv() which...
384 **
385 ** If it finds a value and that value is-a JSON number or is a string
386 ** which looks like an integer or is-a JSON bool/null then it is
387 ** converted to an int. If none of those apply then dflt is returned.
388 */
json_getenv_int(char const * pKey,int dflt)389 int json_getenv_int(char const * pKey, int dflt ){
390   cson_value const * v = json_getenv(pKey);
391   const cson_type_id type = v ? cson_value_type_id(v) : CSON_TYPE_UNDEF;
392   switch(type){
393     case CSON_TYPE_INTEGER:
394     case CSON_TYPE_DOUBLE:
395       return (int)cson_value_get_integer(v);
396     case CSON_TYPE_STRING: {
397       char const * sv = cson_string_cstr(cson_value_get_string(v));
398       assert( (NULL!=sv) && "This is quite unexpected." );
399       return sv ? atoi(sv) : dflt;
400     }
401     case CSON_TYPE_BOOL:
402       return cson_value_get_bool(v) ? 1 : 0;
403     case CSON_TYPE_NULL:
404       return 0;
405     default:
406       return dflt;
407   }
408 }
409 
410 
411 /*
412 ** Wrapper around json_getenv() which tries to evaluate a payload/env
413 ** value as a boolean. Uses mostly the same logic as
414 ** json_getenv_int(), with the addition that string values which
415 ** either start with a digit 1..9 or the letters [tTyY] are considered
416 ** to be true. If this function cannot find a matching key/value then
417 ** dflt is returned. e.g. if it finds the key but the value is-a
418 ** Object then dftl is returned.
419 **
420 ** If an entry is found, this function guarantees that it will return
421 ** either 0 or 1, as opposed to "0 or non-zero", so that clients can
422 ** pass a different value as dflt. Thus they can use, e.g. -1 to know
423 ** whether or not this function found a match (it will return -1 in
424 ** that case).
425 */
json_getenv_bool(char const * pKey,int dflt)426 int json_getenv_bool(char const * pKey, int dflt ){
427   cson_value const * v = json_getenv(pKey);
428   const cson_type_id type = v ? cson_value_type_id(v) : CSON_TYPE_UNDEF;
429   switch(type){
430     case CSON_TYPE_INTEGER:
431     case CSON_TYPE_DOUBLE:
432       return cson_value_get_integer(v) ? 1 : 0;
433     case CSON_TYPE_STRING: {
434       char const * sv = cson_string_cstr(cson_value_get_string(v));
435       assert( (NULL!=sv) && "This is quite unexpected." );
436       if(!*sv || ('0'==*sv)){
437         return 0;
438       }else{
439         return ((('1'<=*sv) && ('9'>=*sv))
440                 || ('t'==*sv) || ('T'==*sv)
441                 || ('y'==*sv) || ('Y'==*sv)
442                 )
443           ? 1 : 0;
444       }
445     }
446     case CSON_TYPE_BOOL:
447       return cson_value_get_bool(v) ? 1 : 0;
448     case CSON_TYPE_NULL:
449       return 0;
450     default:
451       return dflt;
452   }
453 }
454 
455 /*
456 ** Returns the string form of a json_getenv() value, but ONLY If that
457 ** value is-a String. Non-strings are not converted to strings for
458 ** this purpose. Returned memory is owned by g.json or fossil and is
459 ** valid until end-of-app or the given key is replaced in fossil's
460 ** internals via cgi_replace_parameter() and friends or json_setenv().
461 */
json_getenv_cstr(char const * zKey)462 char const * json_getenv_cstr( char const * zKey ){
463   return cson_value_get_cstr( json_getenv(zKey) );
464 }
465 
466 /*
467 ** An extended form of find_option() which tries to look up a combo
468 ** GET/POST/CLI argument.
469 **
470 ** zKey must be the GET/POST parameter key. zCLILong must be the "long
471 ** form" CLI flag (NULL means to use zKey). zCLIShort may be NULL or
472 ** the "short form" CLI flag (if NULL, no short form is used).
473 **
474 ** If argPos is >=0 and no other match is found,
475 ** json_command_arg(argPos) is also checked.
476 **
477 ** On error (no match found) NULL is returned.
478 **
479 ** This ONLY works for String JSON/GET/CLI values, not JSON
480 ** booleans and whatnot.
481 */
json_find_option_cstr2(char const * zKey,char const * zCLILong,char const * zCLIShort,int argPos)482 char const * json_find_option_cstr2(char const * zKey,
483                                     char const * zCLILong,
484                                     char const * zCLIShort,
485                                     int argPos){
486   char const * rc = NULL;
487   assert(NULL != zKey);
488   if(!g.isHTTP){
489     rc = find_option(zCLILong ? zCLILong : zKey,
490                      zCLIShort, 1);
491   }
492   if(!rc && fossil_has_json()){
493     rc = json_getenv_cstr(zKey);
494     if(!rc && zCLIShort){
495       rc = cson_value_get_cstr( cson_object_get( g.json.param.o, zCLIShort) );
496     }
497   }
498   if(!rc && (argPos>=0)){
499     rc = json_command_arg((unsigned char)argPos);
500   }
501   return rc;
502 }
503 
504 /*
505 ** Short-hand form of json_find_option_cstr2(zKey,zCLILong,zCLIShort,-1).
506 */
json_find_option_cstr(char const * zKey,char const * zCLILong,char const * zCLIShort)507 char const * json_find_option_cstr(char const * zKey,
508                                    char const * zCLILong,
509                                    char const * zCLIShort){
510   return json_find_option_cstr2(zKey, zCLILong, zCLIShort, -1);
511 }
512 
513 /*
514 ** The boolean equivalent of json_find_option_cstr().
515 ** If the option is not found, dftl is returned.
516 */
json_find_option_bool(char const * zKey,char const * zCLILong,char const * zCLIShort,int dflt)517 int json_find_option_bool(char const * zKey,
518                           char const * zCLILong,
519                           char const * zCLIShort,
520                           int dflt ){
521   int rc = -1;
522   if(!g.isHTTP){
523     if(NULL != find_option(zCLILong ? zCLILong : zKey,
524                            zCLIShort, 0)){
525       rc = 1;
526     }
527   }
528   if((-1==rc) && fossil_has_json()){
529     rc = json_getenv_bool(zKey,-1);
530   }
531   return (-1==rc) ? dflt : rc;
532 }
533 
534 /*
535 ** The integer equivalent of json_find_option_cstr2().
536 ** If the option is not found, dftl is returned.
537 */
json_find_option_int(char const * zKey,char const * zCLILong,char const * zCLIShort,int dflt)538 int json_find_option_int(char const * zKey,
539                          char const * zCLILong,
540                          char const * zCLIShort,
541                          int dflt ){
542   enum { Magic = -1947854832 };
543   int rc = Magic;
544   if(!g.isHTTP){
545     /* FIXME: use strtol() for better error/dflt handling. */
546     char const * opt = find_option(zCLILong ? zCLILong : zKey,
547                                    zCLIShort, 1);
548     if(NULL!=opt){
549       rc = atoi(opt);
550     }
551   }
552   if(Magic==rc){
553     rc = json_getenv_int(zKey,Magic);
554   }
555   return (Magic==rc) ? dflt : rc;
556 }
557 
558 
559 /*
560 ** Adds v to g.json.param.o using the given key. May cause any prior
561 ** item with that key to be destroyed (depends on current reference
562 ** count for that value). On success, transfers (or shares) ownership
563 ** of v to (or with) g.json.param.o. On error ownership of v is not
564 ** modified.
565 */
json_setenv(char const * zKey,cson_value * v)566 int json_setenv( char const * zKey, cson_value * v ){
567   return cson_object_set( g.json.param.o, zKey, v );
568 }
569 
570 /*
571 ** Guesses a RESPONSE Content-Type value based (primarily) on the
572 ** HTTP_ACCEPT header.
573 **
574 ** It will try to figure out if the client can support
575 ** application/json or application/javascript, and will fall back to
576 ** text/plain if it cannot figure out anything more specific.
577 **
578 ** Returned memory is static and immutable, but if the environment
579 ** changes after calling this then subsequent calls to this function
580 ** might return different (also static/immutable) values.
581 */
json_guess_content_type()582 char const * json_guess_content_type(){
583   char const * cset;
584   char doUtf8;
585   cset = PD("HTTP_ACCEPT_CHARSET",NULL);
586   doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset)))
587     ? 1 : 0;
588   if( g.json.jsonp ){
589     return doUtf8
590       ? "application/javascript; charset=utf-8"
591       : "application/javascript";
592   }else{
593     /*
594       Content-type
595 
596       If the browser does not sent an ACCEPT for application/json
597       then we fall back to text/plain.
598     */
599     char const * cstr;
600     cstr = PD("HTTP_ACCEPT",NULL);
601     if( NULL == cstr ){
602       return doUtf8
603         ? "application/json; charset=utf-8"
604         : "application/json";
605     }else{
606       if( strstr( cstr, "application/json" )
607           || strstr( cstr, "*/*" ) ){
608         return doUtf8
609           ? "application/json; charset=utf-8"
610           : "application/json";
611       }else{
612         return "text/plain";
613       }
614     }
615   }
616 }
617 
618 /*
619  ** Given a request CONTENT_TYPE value, this function returns true
620  ** if it is of a type which the JSON API can ostensibly read.
621  **
622  ** It accepts any of application/json, text/plain, or
623  ** application/javascript. The former is preferred, but was not
624  ** widespread when this API was initially built, so the latter forms
625  ** are permitted as fallbacks.
626  */
json_can_consume_content_type(const char * zType)627 int json_can_consume_content_type(const char * zType){
628   return fossil_strcmp(zType, "application/json")==0
629     || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/
630     || fossil_strcmp(zType,"application/javascript")==0;
631 }
632 
633 /*
634 ** Sends pResponse to the output stream as the response object.  This
635 ** function does no validation of pResponse except to assert() that it
636 ** is not NULL. The caller is responsible for ensuring that it meets
637 ** API response envelope conventions.
638 **
639 ** In CLI mode pResponse is sent to stdout immediately. In HTTP
640 ** mode pResponse replaces any current CGI content but cgi_reply()
641 ** is not called to flush the output.
642 **
643 ** If g.json.jsonp is not NULL then the content type is set to
644 ** application/javascript and the output is wrapped in a jsonp
645 ** wrapper.
646 */
json_send_response(cson_value const * pResponse)647 void json_send_response( cson_value const * pResponse ){
648   assert( NULL != pResponse );
649   if( g.isHTTP ){
650     cgi_reset_content();
651     if( g.json.jsonp ){
652       cgi_printf("%s(",g.json.jsonp);
653     }
654     cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt );
655     if( g.json.jsonp ){
656       cgi_append_content(")",1);
657     }
658   }else{/*CLI mode*/
659     if( g.json.jsonp ){
660       fprintf(stdout,"%s(",g.json.jsonp);
661     }
662     cson_output_FILE( pResponse, stdout, &g.json.outOpt );
663     if( g.json.jsonp ){
664       fwrite(")\n", 2, 1, stdout);
665     }
666   }
667 }
668 
669 /*
670 ** Returns the current request's JSON authentication token, or NULL if
671 ** none is found. The token's memory is owned by (or shared with)
672 ** g.json.
673 **
674 ** If an auth token is found in the GET/POST request data then fossil
675 ** is given that data for use in authentication for this
676 ** session. i.e. the GET/POST data overrides fossil's authentication
677 ** cookie value (if any) and also works with clients which do not
678 ** support cookies.
679 **
680 ** Must be called once before login_check_credentials() is called or
681 ** we will not be able to replace fossil's internal idea of the auth
682 ** info in time (and future changes to that state may cause unexpected
683 ** results).
684 **
685 ** The result of this call are cached for future calls.
686 **
687 ** Special case: if g.useLocalauth is true (i.e. the --localauth flag
688 ** was used to start the fossil server instance) and the current
689 ** connection is "local", any authToken provided by the user is
690 ** ignored and no new token is created: localauth mode trumps the
691 ** authToken.
692 */
json_auth_token()693 cson_value * json_auth_token(){
694   assert(g.json.gc.a && "json_bootstrap_early() was not called!");
695   if( g.json.authToken==0 && g.noPswd==0
696       /* g.noPswd!=0 means the user was logged in via a local
697          connection using --localauth. */
698       ){
699     /* Try to get an authorization token from GET parameter, POSTed
700        JSON, or fossil cookie (in that order). */
701     g.json.authToken = json_getenv(FossilJsonKeys.authToken);
702     if(g.json.authToken
703        && cson_value_is_string(g.json.authToken)
704        && !PD(login_cookie_name(),NULL)){
705       /* tell fossil to use this login info.
706 
707          FIXME?: because the JSON bits don't carry around
708          login_cookie_name(), there is(?) a potential(?) login hijacking
709          window here. We may need to change the JSON auth token to be in
710          the form: login_cookie_name()=...
711 
712          Then again, the hardened cookie value helps ensure that
713          only a proper key/value match is valid.
714       */
715       cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) );
716     }else if( g.isHTTP ){
717       /* try fossil's conventional cookie. */
718       /* Reminder: chicken/egg scenario regarding db access in CLI
719          mode because login_cookie_name() needs the db. CLI
720          mode does not use any authentication, so we don't need
721          to support it here.
722       */
723       char const * zCookie = P(login_cookie_name());
724       if( zCookie && *zCookie ){
725         /* Transfer fossil's cookie to JSON for downstream convenience... */
726         cson_value * v = cson_value_new_string(zCookie, strlen(zCookie));
727         json_gc_add( FossilJsonKeys.authToken, v );
728         g.json.authToken = v;
729       }
730     }
731   }
732   return g.json.authToken;
733 }
734 
735 /*
736 ** If g.json.reqPayload.o is NULL then NULL is returned, else the
737 ** given property is searched for in the request payload.  If found it
738 ** is returned. The returned value is owned by (or shares ownership
739 ** with) g.json, and must NOT be cson_value_free()'d by the
740 ** caller.
741 */
json_req_payload_get(char const * pKey)742 cson_value * json_req_payload_get(char const *pKey){
743   return g.json.reqPayload.o
744     ? cson_object_get(g.json.reqPayload.o,pKey)
745     : NULL;
746 }
747 
748 
749 /*
750 ** Returns non-zero if the json_bootstrap_early() function has already
751 ** been called.  In general, this function should be used sparingly,
752 ** e.g. from low-level support functions like fossil_warning() where
753 ** there is genuine uncertainty about whether (or not) the JSON setup
754 ** has already been called.
755 */
json_is_bootstrapped_early()756 int json_is_bootstrapped_early(){
757   return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
758 }
759 
760 /*
761 ** Initializes some JSON bits which need to be initialized relatively
762 ** early on. It should be called by any routine which might need to
763 ** call into JSON relatively early on in the init process.
764 ** Specifically, early on in cgi_init() and json_cmd_top(), but also
765 ** from any error reporting routines which might be triggered (early
766 ** on in those functions).
767 **
768 ** Initializes g.json.gc and g.json.param. This code does not (and
769 ** must not) rely on any of the fossil environment having been set
770 ** up. e.g. it must not use cgi_parameter() and friends because this
771 ** must be called before those data are initialized.
772 **
773 ** If called multiple times, calls after the first are a no-op.
774 */
json_bootstrap_early()775 void json_bootstrap_early(){
776   cson_value * v;
777 
778   if(g.json.gc.v!=NULL){
779     /* Avoid multiple bootstrappings. */
780     return;
781   }
782   g.json.timerId = fossil_timer_start();
783   /* g.json.gc is our "garbage collector" - where we put JSON values
784      which need a long lifetime but don't have a logical parent to put
785      them in. */
786   v = cson_value_new_array();
787   g.json.gc.v = v;
788   assert(0 != g.json.gc.v);
789   g.json.gc.a = cson_value_get_array(v);
790   assert(0 != g.json.gc.a);
791   cson_value_add_reference(v)
792     /* Needed to allow us to include this value in other JSON
793        containers without transferring ownership to those containers.
794        All other persistent g.json.XXX.v values get appended to
795        g.json.gc.a, and therefore already have a live reference
796        for this purpose. */
797     ;
798 
799   /*
800     g.json.param holds the JSONized counterpart of fossil's
801     cgi_parameter_xxx() family of data. We store them as JSON, as
802     opposed to using fossil's data directly, because we can retain
803     full type information for data this way (as opposed to it always
804     being of type string).
805   */
806   v = cson_value_new_object();
807   g.json.param.v = v;
808   g.json.param.o = cson_value_get_object(v);
809   json_gc_add("$PARAMS", v);
810 }
811 
812 /*
813 ** Appends a warning object to the (pending) JSON response.
814 **
815 ** Code must be a FSL_JSON_W_xxx value from the FossilJsonCodes enum.
816 **
817 ** A Warning object has this JSON structure:
818 **
819 ** { "code":integer, "text":"string" }
820 **
821 ** But the text part is optional.
822 **
823 ** If msg is non-NULL and not empty then it is used as the "text"
824 ** property's value. It is copied, and need not refer to static
825 ** memory.
826 **
827 ** CURRENTLY this code only allows a given warning code to be
828 ** added one time, and elides subsequent warnings. The intention
829 ** is to remove that burden from loops which produce warnings.
830 **
831 ** FIXME: if msg is NULL then use a standard string for
832 ** the given code. If !*msg then elide the "text" property,
833 ** for consistency with how json_err() works.
834 */
json_warn(int code,char const * fmt,...)835 void json_warn( int code, char const * fmt, ... ){
836   cson_object * obj = NULL;
837   assert( (code>FSL_JSON_W_START)
838           && (code<FSL_JSON_W_END)
839           && "Invalid warning code.");
840   assert(g.json.gc.a && "json_bootstrap_early() was not called!");
841   if(!g.json.warnings){
842     g.json.warnings = cson_new_array();
843     assert((NULL != g.json.warnings) && "Alloc error.");
844     json_gc_add("$WARNINGS",cson_array_value(g.json.warnings));
845   }
846   obj = cson_new_object();
847   cson_array_append(g.json.warnings, cson_object_value(obj));
848   cson_object_set(obj,"code",cson_value_new_integer(code));
849   if(fmt && *fmt){
850     /* FIXME: treat NULL fmt as standard warning message for
851        the code, but we don't have those yet.
852     */
853     va_list vargs;
854     char * msg;
855     va_start(vargs,fmt);
856     msg = vmprintf(fmt,vargs);
857     va_end(vargs);
858     cson_object_set(obj,"text", cson_value_new_string(msg,strlen(msg)));
859     free(msg);
860   }
861 }
862 
863 /*
864 ** Splits zStr (which must not be NULL) into tokens separated by the
865 ** given separator character. If doDeHttp is true then each element
866 ** will be passed through dehttpize(), otherwise they are used
867 ** as-is. Note that tokenization happens before dehttpize(),
868 ** which is significant if the ENcoded tokens might contain the
869 ** separator character.
870 **
871 ** Each new element is appended to the given target array object,
872 ** which must not be NULL and ownership of it is not changed by this
873 ** call.
874 **
875 ** On success, returns the number of tokens _encountered_. On error a
876 ** NEGATIVE number is returned - its absolute value is the number of
877 ** tokens encountered (i.e. it reveals which token in zStr was
878 ** problematic).
879 **
880 ** Achtung: leading and trailing whitespace of elements are elided.
881 **
882 ** Achtung: empty elements will be skipped, meaning consecutive empty
883 ** elements are collapsed.
884 */
json_string_split(char const * zStr,char separator,int doDeHttp,cson_array * target)885 int json_string_split( char const * zStr,
886                        char separator,
887                        int doDeHttp,
888                        cson_array * target ){
889   char const * p = zStr /* current byte */;
890   char const * head  /* current start-of-token */;
891   unsigned int len = 0   /* current token's length */;
892   int rc = 0   /* return code (number of added elements)*/;
893   assert( zStr && target );
894   while( fossil_isspace(*p) ){
895     ++p;
896   }
897   head = p;
898   for( ; ; ++p){
899     if( !*p || (separator == *p) ){
900       if( len ){/* append head..(head+len) as next array
901                    element. */
902         cson_value * part = NULL;
903         char * zPart = NULL;
904         ++rc;
905         assert( head != p );
906         zPart = (char*)fossil_malloc(len+1);
907         memcpy(zPart, head, len);
908         zPart[len] = 0;
909         if(doDeHttp){
910           dehttpize(zPart);
911         }
912         if( *zPart ){ /* should only fail if someone manages to url-encoded a NUL byte */
913           part = cson_value_new_string(zPart, strlen(zPart));
914           if( 0 != cson_array_append( target, part ) ){
915             cson_value_free(part);
916             rc = -rc;
917             break;
918           }
919         }else{
920           assert(0 && "i didn't think this was possible!");
921           fprintf(stderr,"%s:%d: My God! It's full of stars!\n",
922                   __FILE__, __LINE__);
923           fossil_exit(1)
924             /* Not fossil_panic() b/c this code needs to be able to
925               run before some of the fossil/json bits are initialized,
926               and fossil_panic() calls into the JSON API.
927             */
928             ;
929         }
930         fossil_free(zPart);
931         len = 0;
932       }
933       if( !*p ){
934         break;
935       }
936       head = p+1;
937       while( *head && fossil_isspace(*head) ){
938         ++head;
939         ++p;
940       }
941       if(!*head){
942         break;
943       }
944       continue;
945     }
946     ++len;
947   }
948   return rc;
949 }
950 
951 /*
952 ** Wrapper around json_string_split(), taking the same first 3
953 ** parameters as this function, but returns the results as a JSON
954 ** Array (if splitting produced tokens) or NULL (if splitting failed
955 ** in any way or produced no tokens).
956 **
957 ** The returned value is owned by the caller. If not NULL then it
958 ** _will_ have a JSON type of Array.
959 */
json_string_split2(char const * zStr,char separator,int doDeHttp)960 cson_value * json_string_split2( char const * zStr,
961                                  char separator,
962                                  int doDeHttp ){
963   cson_array * a = cson_new_array();
964   int rc = json_string_split( zStr, separator, doDeHttp, a );
965   if( 0>=rc ){
966     cson_free_array(a);
967     a = NULL;
968   }
969   return a ? cson_array_value(a) : NULL;
970 }
971 
972 
973 /*
974 ** Performs some common initialization of JSON-related state.  Must be
975 ** called by the json_page_top() and json_cmd_top() dispatching
976 ** functions to set up the JSON stat used by the dispatched functions.
977 **
978 ** Implicitly sets up the login information state in CGI mode, but
979 ** does not perform any permissions checking. It _might_ (haven't
980 ** tested this) die with an error if an auth cookie is malformed.
981 **
982 ** This must be called by the top-level JSON command dispatching code
983 ** before they do any work.
984 **
985 ** This must only be called once, or an assertion may be triggered.
986 */
json_bootstrap_late()987 void json_bootstrap_late(){
988   static char once = 0  /* guard against multiple runs */;
989   char const * zPath = P("PATH_INFO");
990   assert(g.json.gc.a && "json_bootstrap_early() was not called!");
991   assert( (0==once) && "json_bootstrap_late() called too many times!");
992   if( once ){
993     return;
994   }else{
995     once = 1;
996   }
997   assert(g.json.isJsonMode
998          && "g.json.isJsonMode should have been set up by now.");
999   g.json.resultCode = 0;
1000   g.json.cmd.offset = -1;
1001   g.json.jsonp = PD("jsonp",NULL)
1002     /* FIXME: do some sanity checking on g.json.jsonp and ignore it
1003        if it is not halfway reasonable.
1004     */
1005     ;
1006   if( !g.isHTTP && g.fullHttpReply ){
1007     /* workaround for server mode, so we see it as CGI mode. */
1008     g.isHTTP = 1;
1009   }
1010 
1011   if(g.isHTTP){
1012     cgi_set_content_type(json_guess_content_type())
1013       /* reminder: must be done after g.json.jsonp is initialized */
1014       ;
1015 #if 0
1016     /* Calling this seems to trigger an SQLITE_MISUSE warning???
1017        Maybe it's not legal to set the logger more than once?
1018     */
1019     sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0)
1020         /* avoids debug messages on stderr in JSON mode */
1021         ;
1022 #endif
1023   }
1024 
1025   g.json.cmd.v = cson_value_new_array();
1026   g.json.cmd.a = cson_value_get_array(g.json.cmd.v);
1027   json_gc_add( FossilJsonKeys.commandPath, g.json.cmd.v );
1028   /*
1029     The following if/else block translates the PATH_INFO path (in
1030     CLI/server modes) or g.argv (CLI mode) into an internal list so
1031     that we can simplify command dispatching later on.
1032 
1033     Note that translating g.argv this way is overkill but allows us to
1034     avoid CLI-only special-case handling in other code, e.g.
1035     json_command_arg().
1036   */
1037   if( zPath ){/* Either CGI or server mode... */
1038     /* Translate PATH_INFO into JSON array for later convenience. */
1039     json_string_split(zPath, '/', 1, g.json.cmd.a);
1040   }else{/* assume CLI mode */
1041     int i;
1042     char const * arg;
1043     cson_value * part;
1044     for(i = 1/*skip argv[0]*/; i < g.argc; ++i ){
1045       arg = g.argv[i];
1046       if( !arg || !*arg ){
1047         continue;
1048       }
1049       if('-' == *arg){
1050         /* workaround to skip CLI args so that
1051            json_command_arg() does not see them.
1052            This assumes that all arguments come LAST
1053            on the command line.
1054         */
1055         break;
1056       }
1057       part = cson_value_new_string(arg,strlen(arg));
1058       cson_array_append(g.json.cmd.a, part);
1059     }
1060   }
1061 
1062   while(!g.isHTTP){
1063     /* Simulate JSON POST data via input file.  Pedantic reminder:
1064        error handling does not honor user-supplied g.json.outOpt
1065        because outOpt cannot (generically) be configured until after
1066        POST-reading is finished.
1067     */
1068     FILE * inFile = NULL;
1069     char const * jfile = find_option("json-input",NULL,1);
1070     if(!jfile || !*jfile){
1071       break;
1072     }
1073     inFile = (0==strcmp("-",jfile))
1074       ? stdin
1075       : fossil_fopen(jfile,"rb");
1076     if(!inFile){
1077       g.json.resultCode = FSL_JSON_E_FILE_OPEN_FAILED;
1078       fossil_fatal("Could not open JSON file [%s].",jfile)
1079         /* Does not return. */
1080         ;
1081     }
1082     cgi_parse_POST_JSON(inFile, 0);
1083     fossil_fclose(inFile);
1084     break;
1085   }
1086 
1087   /* g.json.reqPayload exists only to simplify some of our access to
1088      the request payload. We currently only use this in the context of
1089      Object payloads, not Arrays, strings, etc.
1090   */
1091   g.json.reqPayload.v = cson_object_get( g.json.post.o, FossilJsonKeys.payload );
1092   if( g.json.reqPayload.v ){
1093     g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v )
1094         /* g.json.reqPayload.o may legally be NULL, which means only that
1095            g.json.reqPayload.v is-not-a Object.
1096         */;
1097   }
1098 
1099   /* Anything which needs json_getenv() and friends should go after
1100      this point.
1101   */
1102 
1103   if(1 == cson_array_length_get(g.json.cmd.a)){
1104     /* special case: if we're at the top path, look for
1105        a "command" request arg which specifies which command
1106        to run.
1107     */
1108     char const * cmd = json_getenv_cstr("command");
1109     if(cmd){
1110       json_string_split(cmd, '/', 0, g.json.cmd.a);
1111       g.json.cmd.commandStr = cmd;
1112     }
1113   }
1114 
1115 
1116   if(!g.json.jsonp){
1117     g.json.jsonp = json_find_option_cstr("jsonp",NULL,NULL);
1118   }
1119   if(!g.isHTTP){
1120     g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/;
1121   }
1122 
1123   {/* set up JSON output formatting options. */
1124     int indent = -1;
1125     indent = json_find_option_int("indent",NULL,"I",-1);
1126     g.json.outOpt.indentation = (0>indent)
1127       ? (g.isHTTP ? 0 : 1)
1128       : (unsigned char)indent;
1129     g.json.outOpt.addNewline = g.isHTTP
1130       ? 0
1131       : (g.json.jsonp ? 0 : 1);
1132   }
1133 
1134   if( g.isHTTP ){
1135     json_auth_token()/* will copy our auth token, if any, to fossil's
1136                         core, which we need before we call
1137                         login_check_credentials(). */;
1138     login_check_credentials()/* populates g.perm */;
1139   }
1140   else{
1141     /* FIXME: we need an option which allows us to skip this. At least
1142        one known command (/json/version) does not need an opened
1143        repo. The problem here is we cannot know which functions need
1144        it from here (because command dispatching hasn't yet happened)
1145        and all other commands rely on the repo being opened before
1146        they are called. A textbook example of lack of foresight :/.
1147      */
1148     db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
1149   }
1150 }
1151 
1152 /*
1153 ** Returns the ndx'th item in the "command path", where index 0 is the
1154 ** position of the "json" part of the path. Returns NULL if ndx is out
1155 ** of bounds or there is no "json" path element.
1156 **
1157 ** In CLI mode the "path" is the list of arguments (skipping argv[0]).
1158 ** In server/CGI modes the path is taken from PATH_INFO.
1159 **
1160 ** The returned bytes are owned by g.json.cmd.v and _may_ be
1161 ** invalidated if that object is modified (depending on how it is
1162 ** modified).
1163 **
1164 ** Note that CLI options are not included in the command path. Use
1165 ** find_option() to get those.
1166 **
1167 */
json_command_arg(unsigned short ndx)1168 char const * json_command_arg(unsigned short ndx){
1169   cson_array * ar = g.json.cmd.a;
1170   assert((NULL!=ar) && "Internal error. Was json_bootstrap_late() called?");
1171   assert((g.argc>1) && "Internal error - we never should have gotten this far.");
1172   if( g.json.cmd.offset < 0 ){
1173     /* first-time setup. */
1174     short i = 0;
1175 #define NEXT cson_string_cstr(          \
1176                  cson_value_get_string( \
1177                    cson_array_get(ar,i) \
1178                    ))
1179     char const * tok = NEXT;
1180     while( tok ){
1181       if( g.isHTTP/*workaround for "abbreviated name" in CLI mode*/
1182           ? (0==strncmp("json",tok,4))
1183           : (0==strcmp(g.argv[1],tok))
1184           ){
1185         g.json.cmd.offset = i;
1186         break;
1187       }
1188       ++i;
1189       tok = NEXT;
1190     }
1191   }
1192 #undef NEXT
1193   if(g.json.cmd.offset < 0){
1194     return NULL;
1195   }else{
1196     ndx = g.json.cmd.offset + ndx;
1197     return cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmd.offset + ndx )));
1198   }
1199 }
1200 
1201 /* Returns the C-string form of json_auth_token(), or NULL
1202 ** if json_auth_token() returns NULL.
1203 */
json_auth_token_cstr()1204 char const * json_auth_token_cstr(){
1205   return cson_value_get_cstr( json_auth_token() );
1206 }
1207 
1208 /*
1209 ** Returns the JsonPageDef with the given name, or NULL if no match is
1210 ** found.
1211 **
1212 ** head must be a pointer to an array of JsonPageDefs in which the
1213 ** last entry has a NULL name.
1214 */
json_handler_for_name(char const * name,JsonPageDef const * head)1215 JsonPageDef const * json_handler_for_name( char const * name, JsonPageDef const * head ){
1216   JsonPageDef const * pageDef = head;
1217   assert( head != NULL );
1218   if(name && *name) for( ; pageDef->name; ++pageDef ){
1219     if( 0 == strcmp(name, pageDef->name) ){
1220       return pageDef;
1221     }
1222   }
1223   return NULL;
1224 }
1225 
1226 /*
1227 ** Given a Fossil/JSON result code, this function "dumbs it down"
1228 ** according to the current value of g.json.errorDetailParanoia. The
1229 ** dumbed-down value is returned.
1230 **
1231 ** This function assert()s that code is in the inclusive range 0 to
1232 ** 9999.
1233 **
1234 ** Note that WARNING codes (1..999) are never dumbed down.
1235 **
1236 */
json_dumbdown_rc(int code)1237 static int json_dumbdown_rc( int code ){
1238   if(!g.json.errorDetailParanoia
1239      || !code
1240      || ((code>=FSL_JSON_W_START) && (code<FSL_JSON_W_END))){
1241     return code;
1242   }else{
1243     int modulo = 0;
1244     assert((code >= 1000) && (code <= 9999) && "Invalid Fossil/JSON code.");
1245     switch( g.json.errorDetailParanoia ){
1246       case 1: modulo = 10; break;
1247       case 2: modulo = 100; break;
1248       case 3: modulo = 1000; break;
1249       default: break;
1250     }
1251     if( modulo ) code = code - (code % modulo);
1252     return code;
1253   }
1254 }
1255 
1256 /*
1257 ** Convenience routine which converts a Julian time value into a Unix
1258 ** Epoch timestamp. Requires the db, so this cannot be used before the
1259 ** repo is opened (will trigger a fatal error in db_xxx()). The returned
1260 ** value is owned by the caller.
1261 */
json_julian_to_timestamp(double j)1262 cson_value * json_julian_to_timestamp(double j){
1263   return cson_value_new_integer((cson_int_t)
1264            db_int64(0,"SELECT cast(strftime('%%s',%lf) as int)",j)
1265                                 );
1266 }
1267 
1268 /*
1269 ** Returns a timestamp value.
1270 */
json_timestamp()1271 cson_int_t json_timestamp(){
1272   return (cson_int_t)time(0);
1273 }
1274 
1275 /*
1276 ** Returns a new JSON value (owned by the caller) representing
1277 ** a timestamp. If timeVal is < 0 then time(0) is used to fetch
1278 ** the time, else timeVal is used as-is. The returned value is
1279 ** owned by the caller.
1280 */
json_new_timestamp(cson_int_t timeVal)1281 cson_value * json_new_timestamp(cson_int_t timeVal){
1282   return cson_value_new_integer((timeVal<0) ? (cson_int_t)time(0) : timeVal);
1283 }
1284 
1285 /*
1286 ** Internal helper for json_create_response(). Appends the first
1287 ** g.json.dispatchDepth elements of g.json.cmd.a, skipping the first
1288 ** one (the "json" part), to a string and returns that string value
1289 ** (which is owned by the caller).
1290 */
json_response_command_path()1291 static cson_value * json_response_command_path(){
1292   if(!g.json.cmd.a){
1293     return NULL;
1294   }else{
1295     cson_value * rc = NULL;
1296     Blob path = empty_blob;
1297     unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
1298     unsigned int i = 1;
1299     for( ; i < aLen; ++i ){
1300       char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
1301       if(!part){
1302 #if 1
1303           fossil_warning("Iterating further than expected in %s.",
1304                        __FILE__);
1305 #endif
1306           break;
1307       }
1308       blob_appendf(&path,"%s%s", (i>1 ? "/": ""), part);
1309     }
1310     rc = json_new_string((blob_size(&path)>0)
1311                          ? blob_buffer(&path)
1312                          : "")
1313       /* reminder; we need an empty string instead of NULL
1314          in this case, to avoid what outwardly looks like
1315          (but is not) an allocation error in
1316          json_create_response().
1317       */
1318       ;
1319     blob_reset(&path);
1320     return rc;
1321   }
1322 }
1323 
1324 /*
1325 ** Returns a JSON Object representation of the global g object.
1326 ** Returned value is owned by the caller.
1327 */
json_g_to_json()1328 cson_value * json_g_to_json(){
1329   cson_object * o = NULL;
1330   cson_object * pay = NULL;
1331   pay = o = cson_new_object();
1332 
1333 #define INT(OBJ,K) cson_object_set(o, #K, json_new_int(OBJ.K))
1334 #define CSTR(OBJ,K) cson_object_set(o, #K, OBJ.K ? json_new_string(OBJ.K) : cson_value_null())
1335 #define VAL(K,V) cson_object_set(o, #K, (V) ? (V) : cson_value_null())
1336   VAL(capabilities, json_cap_value());
1337   INT(g, argc);
1338   INT(g, isConst);
1339   CSTR(g, zConfigDbName);
1340   INT(g, repositoryOpen);
1341   INT(g, localOpen);
1342   INT(g, minPrefix);
1343   INT(g, fSqlTrace);
1344   INT(g, fSqlStats);
1345   INT(g, fSqlPrint);
1346   INT(g, fQuiet);
1347   INT(g, fHttpTrace);
1348   INT(g, fSystemTrace);
1349   INT(g, fNoSync);
1350   INT(g, iErrPriority);
1351   INT(g, sslNotAvailable);
1352   INT(g, cgiOutput);
1353   INT(g, xferPanic);
1354   INT(g, fullHttpReply);
1355   INT(g, xlinkClusterOnly);
1356   INT(g, fTimeFormat);
1357   INT(g, markPrivate);
1358   INT(g, clockSkewSeen);
1359   INT(g, isHTTP);
1360   INT(g.url, isFile);
1361   INT(g.url, isHttps);
1362   INT(g.url, isSsh);
1363   INT(g.url, port);
1364   INT(g.url, dfltPort);
1365   INT(g, useLocalauth);
1366   INT(g, noPswd);
1367   INT(g, userUid);
1368   INT(g, rcvid);
1369   INT(g, okCsrf);
1370   INT(g, thTrace);
1371   INT(g, isHome);
1372   INT(g, nAux);
1373   INT(g, allowSymlinks);
1374 
1375   CSTR(g, zOpenRevision);
1376   CSTR(g, zLocalRoot);
1377   CSTR(g, zPath);
1378   CSTR(g, zExtra);
1379   CSTR(g, zBaseURL);
1380   CSTR(g, zTop);
1381   CSTR(g, zContentType);
1382   CSTR(g, zErrMsg);
1383   CSTR(g.url, name);
1384   CSTR(g.url, hostname);
1385   CSTR(g.url, protocol);
1386   CSTR(g.url, path);
1387   CSTR(g.url, user);
1388   CSTR(g.url, passwd);
1389   CSTR(g.url, canonical);
1390   CSTR(g.url, proxyAuth);
1391   CSTR(g.url, fossil);
1392   CSTR(g, zLogin);
1393   CSTR(g, zSSLIdentity);
1394   CSTR(g, zIpAddr);
1395   CSTR(g, zNonce);
1396   CSTR(g, zCsrfToken);
1397 
1398   o = cson_new_object();
1399   cson_object_set(pay, "json", cson_object_value(o) );
1400   INT(g.json, isJsonMode);
1401   INT(g.json, resultCode);
1402   INT(g.json, errorDetailParanoia);
1403   INT(g.json, dispatchDepth);
1404   VAL(authToken, g.json.authToken);
1405   CSTR(g.json, jsonp);
1406   VAL(gc, g.json.gc.v);
1407   VAL(cmd, g.json.cmd.v);
1408   VAL(param, g.json.param.v);
1409   VAL(POST, g.json.post.v);
1410   VAL(warnings, cson_array_value(g.json.warnings));
1411   /*cson_output_opt outOpt;*/
1412 
1413 
1414 #undef INT
1415 #undef CSTR
1416 #undef VAL
1417   return cson_object_value(pay);
1418 }
1419 
1420 
1421 /*
1422 ** Creates a new Fossil/JSON response envelope skeleton.  It is owned
1423 ** by the caller, who must eventually free it using cson_value_free(),
1424 ** or add it to a cson container to transfer ownership. Returns NULL
1425 ** on error.
1426 **
1427 ** If payload is not NULL and resultCode is 0 then it is set as the
1428 ** "payload" property of the returned object.  If resultCode is 0 then
1429 ** it defaults to g.json.resultCode. If resultCode is (or defaults to)
1430 ** non-zero and payload is not NULL then this function calls
1431 ** cson_value_free(payload) and does not insert the payload into the
1432 ** response. In either case, ownership of payload is transfered to (or
1433 ** shared with, if the caller holds a reference) this function.
1434 **
1435 ** pMsg is an optional message string property (resultText) of the
1436 ** response. If resultCode is non-0 and pMsg is NULL then
1437 ** json_err_cstr() is used to get the error string. The caller may
1438 ** provide his own or may use an empty string to suppress the
1439 ** resultText property.
1440 **
1441 */
json_create_response(int resultCode,char const * pMsg,cson_value * payload)1442 static cson_value * json_create_response( int resultCode,
1443                                           char const * pMsg,
1444                                           cson_value * payload){
1445   cson_value * v = NULL;
1446   cson_value * tmp = NULL;
1447   cson_object * o = NULL;
1448   int rc;
1449   resultCode = json_dumbdown_rc(resultCode ? resultCode : g.json.resultCode);
1450   o = cson_new_object();
1451   v = cson_object_value(o);
1452   if( ! o ) return NULL;
1453 #define SET(K) if(!tmp) goto cleanup; \
1454   cson_value_add_reference(tmp);      \
1455   rc = cson_object_set( o, K, tmp );  \
1456   cson_value_free(tmp);               \
1457   if(rc) do{                          \
1458     tmp = NULL;                       \
1459     goto cleanup;                     \
1460   }while(0)
1461 
1462   tmp = json_new_string(MANIFEST_UUID);
1463   SET("fossil");
1464 
1465   tmp = json_new_timestamp(-1);
1466   SET(FossilJsonKeys.timestamp);
1467 
1468   if( 0 != resultCode ){
1469     if( ! pMsg ){
1470       pMsg = g.zErrMsg;
1471       if(!pMsg){
1472         pMsg = json_err_cstr(resultCode);
1473       }
1474     }
1475     tmp = json_new_string(json_rc_cstr(resultCode));
1476     SET(FossilJsonKeys.resultCode);
1477   }
1478 
1479   if( pMsg && *pMsg ){
1480     tmp = json_new_string(pMsg);
1481     SET(FossilJsonKeys.resultText);
1482   }
1483 
1484   if(g.json.cmd.commandStr){
1485     tmp = json_new_string(g.json.cmd.commandStr);
1486   }else{
1487     tmp = json_response_command_path();
1488   }
1489   if(!tmp){
1490     tmp = json_new_string("???");
1491   }
1492   SET("command");
1493 
1494   tmp = json_getenv(FossilJsonKeys.requestId);
1495   if( tmp ) cson_object_set( o, FossilJsonKeys.requestId, tmp );
1496 
1497   if(0){/* these are only intended for my own testing...*/
1498     if(g.json.cmd.v){
1499       tmp = g.json.cmd.v;
1500       SET("$commandPath");
1501     }
1502     if(g.json.param.v){
1503       tmp = g.json.param.v;
1504       SET("$params");
1505     }
1506     if(0){/*Only for debugging, add some info to the response.*/
1507       tmp = cson_value_new_integer( g.json.cmd.offset );
1508       SET("cmd.offset");
1509       tmp = cson_value_new_bool( g.isHTTP );
1510       SET("isCGI");
1511     }
1512   }
1513 
1514   if(fossil_timer_is_active(g.json.timerId)){
1515     /* This is, philosophically speaking, not quite the right place
1516        for ending the timer, but this is the one function which all of
1517        the JSON exit paths use (and they call it after processing,
1518        just before they end).
1519     */
1520     sqlite3_uint64 span = fossil_timer_stop(g.json.timerId);
1521     /* I'm actually seeing sub-uSec runtimes in some tests, but a time of
1522        0 is "just kinda wrong".
1523     */
1524     cson_object_set(o,"procTimeUs", cson_value_new_integer((cson_int_t)span));
1525     span /= 1000/*for milliseconds */;
1526     cson_object_set(o,"procTimeMs", cson_value_new_integer((cson_int_t)span));
1527     assert(!fossil_timer_is_active(g.json.timerId));
1528     g.json.timerId = -1;
1529   }
1530   if(g.json.warnings){
1531     tmp = cson_array_value(g.json.warnings);
1532     SET("warnings");
1533   }
1534 
1535   /* Only add the payload to SUCCESS responses. Else delete it. */
1536   if( NULL != payload ){
1537     if( resultCode ){
1538       cson_value_free(payload);
1539       payload = NULL;
1540     }else{
1541       tmp = payload;
1542       SET(FossilJsonKeys.payload);
1543     }
1544   }
1545 
1546   if((g.perm.Admin||g.perm.Setup)
1547      && json_find_option_bool("debugFossilG","json-debug-g",NULL,0)
1548      ){
1549     tmp = json_g_to_json();
1550     SET("g");
1551   }
1552 
1553 #undef SET
1554   goto ok;
1555   cleanup:
1556   cson_value_free(v);
1557   v = NULL;
1558   ok:
1559   return v;
1560 }
1561 
1562 /*
1563 ** Outputs a JSON error response to either the cgi_xxx() family of
1564 ** buffers (in CGI/server mode) or stdout (in CLI mode). If rc is 0
1565 ** then g.json.resultCode is used. If that is also 0 then the "Unknown
1566 ** Error" code is used.
1567 **
1568 ** If g.isHTTP then the generated JSON error response object replaces
1569 ** any currently buffered page output. Because the output goes via
1570 ** the cgi_xxx() family of functions, this function inherits any
1571 ** compression which fossil does for its output.
1572 **
1573 ** If alsoOutput is true AND g.isHTTP then cgi_reply() is called to
1574 ** flush the output (and headers). Generally only do this if you are
1575 ** about to call exit().
1576 **
1577 ** If !g.isHTTP then alsoOutput is ignored and all output is sent to
1578 ** stdout immediately.
1579 **
1580 ** For generating the resultText property: if msg is not NULL then it
1581 ** is used as-is. If it is NULL then g.zErrMsg is checked, and if that
1582 ** is NULL then json_err_cstr(code) is used.
1583 */
json_err(int code,char const * msg,int alsoOutput)1584 void json_err( int code, char const * msg, int alsoOutput ){
1585   int rc = code ? code : (g.json.resultCode
1586                           ? g.json.resultCode
1587                           : FSL_JSON_E_UNKNOWN);
1588   cson_value * resp = NULL;
1589   if(g.json.isJsonMode==0) return;
1590   rc = json_dumbdown_rc(rc);
1591   if( rc && !msg ){
1592     msg = g.zErrMsg;
1593     if(!msg){
1594       msg = json_err_cstr(rc);
1595     }
1596   }
1597   resp = json_create_response(rc, msg, NULL);
1598   if(!resp){
1599     /* about the only error case here is out-of-memory. DO NOT
1600        call fossil_panic() or fossil_fatal() here because those
1601        allocate.
1602     */
1603     fprintf(stderr, "%s: Fatal error: could not allocate "
1604             "response object.\n", g.argv[0]);
1605     fossil_exit(1);
1606   }
1607   if( g.isHTTP ){
1608     if(alsoOutput){
1609       json_send_response(resp);
1610     }else{
1611       /* almost a duplicate of json_send_response() :( */
1612       cgi_reset_content();
1613       if( g.json.jsonp ){
1614         cgi_printf("%s(",g.json.jsonp);
1615       }
1616       cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt );
1617       if( g.json.jsonp ){
1618         cgi_append_content(")",1);
1619       }
1620     }
1621   }else{
1622     json_send_response(resp);
1623   }
1624   cson_value_free(resp);
1625 }
1626 
1627 /*
1628 ** Sets g.json.resultCode and g.zErrMsg, but does not report the error
1629 ** via json_err(). Returns the code passed to it.
1630 **
1631 ** code must be in the inclusive range 1000..9999.
1632 */
json_set_err(int code,char const * fmt,...)1633 int json_set_err( int code, char const * fmt, ... ){
1634   assert( (code>=1000) && (code<=9999) );
1635   free(g.zErrMsg);
1636   g.json.resultCode = code;
1637   if(!fmt || !*fmt){
1638     g.zErrMsg = mprintf("%s", json_err_cstr(code));
1639   }else{
1640     va_list vargs;
1641     char * msg;
1642     va_start(vargs,fmt);
1643     msg = vmprintf(fmt, vargs);
1644     va_end(vargs);
1645     g.zErrMsg = msg;
1646   }
1647   return code;
1648 }
1649 
1650 /*
1651 ** Iterates through a prepared SELECT statement and converts each row
1652 ** to a JSON object. If pTgt is not NULL then this function will
1653 ** append the results to pTgt and return cson_array_value(pTgt). If
1654 ** pTgt is NULL then a new Array object is created and returned (owned
1655 ** by the caller). Each row of pStmt is converted to an Object and
1656 ** appended to the array. If the result set has no rows AND pTgt is
1657 ** NULL then NULL (not an empty array) is returned.
1658 */
json_stmt_to_array_of_obj(Stmt * pStmt,cson_array * pTgt)1659 cson_value * json_stmt_to_array_of_obj(Stmt *pStmt,
1660                                        cson_array * pTgt){
1661   cson_array * a = pTgt;
1662   char const * warnMsg = NULL;
1663   cson_value * colNamesV = NULL;
1664   cson_array * colNames = NULL;
1665   while( (SQLITE_ROW==db_step(pStmt)) ){
1666     cson_value * row = NULL;
1667     if(!a){
1668       a = cson_new_array();
1669       assert(NULL!=a);
1670     }
1671     if(!colNames){
1672       colNamesV = cson_sqlite3_column_names(pStmt->pStmt);
1673       assert(NULL != colNamesV);
1674       /*Why? cson_value_add_reference(colNamesV) avoids an ownership problem*/;
1675       colNames = cson_value_get_array(colNamesV);
1676       assert(NULL != colNames);
1677     }
1678     row = cson_sqlite3_row_to_object2(pStmt->pStmt, colNames);
1679     if(!row && !warnMsg){
1680       warnMsg = "Could not convert at least one result row to JSON.";
1681       continue;
1682     }
1683     if( 0 != cson_array_append(a, row) ){
1684       cson_value_free(row);
1685       if(pTgt != a) {
1686         cson_free_array(a);
1687       }
1688       assert( 0 && "Alloc error.");
1689       return NULL;
1690     }
1691   }
1692   cson_value_free(colNamesV);
1693   if(warnMsg){
1694     json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, "%s", warnMsg );
1695   }
1696   return cson_array_value(a);
1697 }
1698 
1699 /*
1700 ** Works just like json_stmt_to_array_of_obj(), but each row in the
1701 ** result set is represented as an Array of values instead of an
1702 ** Object (key/value pairs). If pTgt is NULL and the statement
1703 ** has no results then NULL is returned, not an empty array.
1704 */
json_stmt_to_array_of_array(Stmt * pStmt,cson_array * pTgt)1705 cson_value * json_stmt_to_array_of_array(Stmt *pStmt,
1706                                          cson_array * pTgt){
1707   cson_array * a = pTgt;
1708   while( (SQLITE_ROW==db_step(pStmt)) ){
1709     cson_value * row = NULL;
1710     if(!a){
1711       a = cson_new_array();
1712       assert(NULL!=a);
1713     }
1714     row = cson_sqlite3_row_to_array(pStmt->pStmt);
1715     cson_array_append(a, row);
1716   }
1717   return cson_array_value(a);
1718 }
1719 
json_stmt_to_array_of_values(Stmt * pStmt,int resultColumn,cson_array * pTgt)1720 cson_value * json_stmt_to_array_of_values(Stmt *pStmt,
1721                                           int resultColumn,
1722                                           cson_array * pTgt){
1723   cson_array * a = pTgt;
1724   while( (SQLITE_ROW==db_step(pStmt)) ){
1725     cson_value * row = cson_sqlite3_column_to_value(pStmt->pStmt,
1726                                                     resultColumn);
1727     if(row){
1728       if(!a){
1729         a = cson_new_array();
1730         assert(NULL!=a);
1731       }
1732       cson_array_append(a, row);
1733     }
1734   }
1735   return cson_array_value(a);
1736 }
1737 
1738 /*
1739 ** Executes the given SQL and runs it through
1740 ** json_stmt_to_array_of_obj(), returning the result of that
1741 ** function. If resetBlob is true then blob_reset(pSql) is called
1742 ** after preparing the query.
1743 **
1744 ** pTgt has the same semantics as described for
1745 ** json_stmt_to_array_of_obj().
1746 **
1747 ** FIXME: change this to take a (char const *) instead of a blob,
1748 ** to simplify the trivial use-cases (which don't need a Blob).
1749 */
json_sql_to_array_of_obj(Blob * pSql,cson_array * pTgt,int resetBlob)1750 cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_array * pTgt,
1751                                       int resetBlob){
1752   Stmt q = empty_Stmt;
1753   cson_value * pay = NULL;
1754   assert( blob_size(pSql) > 0 );
1755   db_prepare(&q, "%s", blob_str(pSql) /*safe-for-%s*/);
1756   if(resetBlob){
1757     blob_reset(pSql);
1758   }
1759   pay = json_stmt_to_array_of_obj(&q, pTgt);
1760   db_finalize(&q);
1761   return pay;
1762 
1763 }
1764 
1765 /*
1766 ** If the given COMMIT rid has any tags associated with it, this
1767 ** function returns a JSON Array containing the tag names (owned by
1768 ** the caller), else it returns NULL.
1769 **
1770 ** See info_tags_of_checkin() for more details (this is simply a JSON
1771 ** wrapper for that function).
1772 **
1773 ** If there are no tags then this function returns NULL, not an empty
1774 ** Array.
1775 */
json_tags_for_checkin_rid(int rid,int propagatingOnly)1776 cson_value * json_tags_for_checkin_rid(int rid, int propagatingOnly){
1777   cson_value * v = NULL;
1778   char * tags = info_tags_of_checkin(rid, propagatingOnly);
1779   if(tags){
1780     if(*tags){
1781       v = json_string_split2(tags,',',0);
1782     }
1783     free(tags);
1784   }
1785   return v;
1786 }
1787 
1788 /*
1789  ** Returns a "new" value representing the boolean value of zVal
1790  ** (false if zVal is NULL). Note that cson does not really allocate
1791  ** any memory for boolean values, but they "should" (for reasons of
1792  ** style and philosophy) be cleaned up like any other values (but
1793  ** it's a no-op for bools).
1794  */
json_value_to_bool(cson_value const * zVal)1795 cson_value * json_value_to_bool(cson_value const * zVal){
1796   return cson_value_get_bool(zVal)
1797     ? cson_value_true()
1798     : cson_value_false();
1799 }
1800 
1801 /*
1802 ** Impl of /json/resultCodes
1803 **
1804 */
json_page_resultCodes()1805 cson_value * json_page_resultCodes(){
1806     cson_array * list = cson_new_array();
1807     cson_object * obj = NULL;
1808     cson_string * kRC;
1809     cson_string * kSymbol;
1810     cson_string * kNumber;
1811     cson_string * kDesc;
1812     cson_array_reserve( list, 35 );
1813     kRC = cson_new_string("resultCode",10);
1814     kSymbol = cson_new_string("cSymbol",7);
1815     kNumber = cson_new_string("number",6);
1816     kDesc = cson_new_string("description",11);
1817 #define C(K) obj = cson_new_object(); \
1818     cson_object_set_s(obj, kRC, json_new_string(json_rc_cstr(FSL_JSON_E_##K)) ); \
1819     cson_object_set_s(obj, kSymbol, json_new_string("FSL_JSON_E_"#K) );             \
1820     cson_object_set_s(obj, kNumber, cson_value_new_integer(FSL_JSON_E_##K) );        \
1821     cson_object_set_s(obj, kDesc, json_new_string(json_err_cstr(FSL_JSON_E_##K))); \
1822     cson_array_append( list, cson_object_value(obj) ); obj = NULL;
1823 
1824     C(GENERIC);
1825     C(INVALID_REQUEST);
1826     C(UNKNOWN_COMMAND);
1827     C(UNKNOWN);
1828     C(TIMEOUT);
1829     C(ASSERT);
1830     C(ALLOC);
1831     C(NYI);
1832     C(PANIC);
1833     C(MANIFEST_READ_FAILED);
1834     C(FILE_OPEN_FAILED);
1835 
1836     C(AUTH);
1837     C(MISSING_AUTH);
1838     C(DENIED);
1839     C(WRONG_MODE);
1840     C(LOGIN_FAILED);
1841     C(LOGIN_FAILED_NOSEED);
1842     C(LOGIN_FAILED_NONAME);
1843     C(LOGIN_FAILED_NOPW);
1844     C(LOGIN_FAILED_NOTFOUND);
1845 
1846     C(USAGE);
1847     C(INVALID_ARGS);
1848     C(MISSING_ARGS);
1849     C(AMBIGUOUS_UUID);
1850     C(UNRESOLVED_UUID);
1851     C(RESOURCE_ALREADY_EXISTS);
1852     C(RESOURCE_NOT_FOUND);
1853 
1854     C(DB);
1855     C(STMT_PREP);
1856     C(STMT_BIND);
1857     C(STMT_EXEC);
1858     C(DB_LOCKED);
1859     C(DB_NEEDS_REBUILD);
1860     C(DB_NOT_FOUND);
1861     C(DB_NOT_VALID);
1862 #undef C
1863     return cson_array_value(list);
1864 }
1865 
1866 
1867 /*
1868 ** /json/version implementation.
1869 **
1870 ** Returns the payload object (owned by the caller).
1871 */
json_page_version()1872 cson_value * json_page_version(){
1873   cson_value * jval = NULL;
1874   cson_object * jobj = NULL;
1875   jval = cson_value_new_object();
1876   jobj = cson_value_get_object(jval);
1877 #define FSET(X,K) cson_object_set( jobj, K, cson_value_new_string(X,strlen(X)))
1878   FSET(MANIFEST_UUID,"manifestUuid");
1879   FSET(MANIFEST_VERSION,"manifestVersion");
1880   FSET(MANIFEST_DATE,"manifestDate");
1881   FSET(MANIFEST_YEAR,"manifestYear");
1882   FSET(RELEASE_VERSION,"releaseVersion");
1883   cson_object_set( jobj, "releaseVersionNumber",
1884                    cson_value_new_integer(RELEASE_VERSION_NUMBER) );
1885   cson_object_set( jobj, "resultCodeParanoiaLevel",
1886                    cson_value_new_integer(g.json.errorDetailParanoia) );
1887   FSET(FOSSIL_JSON_API_VERSION, "jsonApiVersion" );
1888 #undef FSET
1889   return jval;
1890 }
1891 
1892 
1893 /*
1894 ** Returns the current user's capabilities string as a String value.
1895 ** Returned value is owned by the caller, and will only be NULL if
1896 ** g.userUid is invalid or an out of memory error. Or, it turns out,
1897 ** in CLI mode (where there is no logged-in user).
1898 */
json_cap_value()1899 cson_value * json_cap_value(){
1900   if(g.userUid<=0){
1901     return NULL;
1902   }else{
1903     Stmt q = empty_Stmt;
1904     cson_value * val = NULL;
1905     db_prepare(&q, "SELECT cap FROM user WHERE uid=%d", g.userUid);
1906     if( db_step(&q)==SQLITE_ROW ){
1907       char const * str = (char const *)sqlite3_column_text(q.pStmt,0);
1908       if( str ){
1909         val = json_new_string(str);
1910       }
1911     }
1912     db_finalize(&q);
1913     return val;
1914   }
1915 }
1916 
1917 /*
1918 ** Implementation for /json/cap
1919 **
1920 ** Returned object contains details about the "capabilities" of the
1921 ** current user (what he may/may not do).
1922 **
1923 ** This is primarily intended for debuggering, but may have
1924 ** a use in client code. (?)
1925 */
json_page_cap()1926 cson_value * json_page_cap(){
1927   cson_value * payload = cson_value_new_object();
1928   cson_value * sub = cson_value_new_object();
1929   Stmt q;
1930   cson_object * obj = cson_value_get_object(payload);
1931   db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", g.userUid);
1932   if( db_step(&q)==SQLITE_ROW ){
1933     /* reminder: we don't use g.zLogin because it's 0 for the guest
1934        user and the HTML UI appears to currently allow the name to be
1935        changed (but doing so would break other code). */
1936     char const * str = (char const *)sqlite3_column_text(q.pStmt,0);
1937     if( str ){
1938       cson_object_set( obj, "name",
1939                        cson_value_new_string(str,strlen(str)) );
1940     }
1941     str = (char const *)sqlite3_column_text(q.pStmt,1);
1942     if( str ){
1943       cson_object_set( obj, "capabilities",
1944                        cson_value_new_string(str,strlen(str)) );
1945     }
1946   }
1947   db_finalize(&q);
1948   cson_object_set( obj, "permissionFlags", sub );
1949   obj = cson_value_get_object(sub);
1950 
1951 #define ADD(X,K) cson_object_set(obj, K, cson_value_new_bool(g.perm.X))
1952   ADD(Setup,"setup");
1953   ADD(Admin,"admin");
1954   ADD(Password,"password");
1955   ADD(Query,"query"); /* don't think this one is actually used */
1956   ADD(Write,"checkin");
1957   ADD(Read,"checkout");
1958   ADD(Hyperlink,"history");
1959   ADD(Clone,"clone");
1960   ADD(RdWiki,"readWiki");
1961   ADD(NewWiki,"createWiki");
1962   ADD(ApndWiki,"appendWiki");
1963   ADD(WrWiki,"editWiki");
1964   ADD(ModWiki,"moderateWiki");
1965   ADD(RdTkt,"readTicket");
1966   ADD(NewTkt,"createTicket");
1967   ADD(ApndTkt,"appendTicket");
1968   ADD(WrTkt,"editTicket");
1969   ADD(ModTkt,"moderateTicket");
1970   ADD(Attach,"attachFile");
1971   ADD(TktFmt,"createTicketReport");
1972   ADD(RdAddr,"readPrivate");
1973   ADD(Zip,"zip");
1974   ADD(Private,"xferPrivate");
1975   ADD(WrUnver,"writeUnversioned");
1976   ADD(RdForum,"readForum");
1977   ADD(WrForum,"writeForum");
1978   ADD(WrTForum,"writeTrustedForum");
1979   ADD(ModForum,"moderateForum");
1980   ADD(AdminForum,"adminForum");
1981   ADD(EmailAlert,"emailAlert");
1982   ADD(Announce,"announce");
1983   ADD(Debug,"debug");
1984   ADD(Chat,"chat");
1985 #undef ADD
1986   return payload;
1987 }
1988 
1989 /*
1990 ** Implementation of the /json/stat page/command.
1991 **
1992 */
json_page_stat()1993 cson_value * json_page_stat(){
1994   i64 t, fsize;
1995   int n, m;
1996   int full;
1997   enum { BufLen = 1000 };
1998   char zBuf[BufLen];
1999   cson_value * jv = NULL;
2000   cson_object * jo = NULL;
2001   cson_value * jv2 = NULL;
2002   cson_object * jo2 = NULL;
2003   char * zTmp = NULL;
2004   if( !g.perm.Read ){
2005     json_set_err(FSL_JSON_E_DENIED,
2006                  "Requires 'o' permissions.");
2007     return NULL;
2008   }
2009   full = json_find_option_bool("full",NULL,"f",
2010               json_find_option_bool("verbose",NULL,"v",0));
2011 #define SETBUF(O,K) cson_object_set(O, K, cson_value_new_string(zBuf, strlen(zBuf)));
2012 
2013   jv = cson_value_new_object();
2014   jo = cson_value_get_object(jv);
2015 
2016   zTmp = db_get("project-name",NULL);
2017   cson_object_set(jo, "projectName", json_new_string(zTmp));
2018   free(zTmp);
2019   zTmp = db_get("project-description",NULL);
2020   cson_object_set(jo, "projectDescription", json_new_string(zTmp));
2021   free(zTmp);
2022   zTmp = NULL;
2023   fsize = file_size(g.zRepositoryName, ExtFILE);
2024   cson_object_set(jo, "repositorySize",
2025                   cson_value_new_integer((cson_int_t)fsize));
2026 
2027   if(full){
2028     n = db_int(0, "SELECT count(*) FROM blob");
2029     m = db_int(0, "SELECT count(*) FROM delta");
2030     cson_object_set(jo, "blobCount", cson_value_new_integer((cson_int_t)n));
2031     cson_object_set(jo, "deltaCount", cson_value_new_integer((cson_int_t)m));
2032     if( n>0 ){
2033       int a, b;
2034       Stmt q;
2035       db_prepare(&q, "SELECT total(size), avg(size), max(size)"
2036                  " FROM blob WHERE size>0");
2037       db_step(&q);
2038       t = db_column_int64(&q, 0);
2039       cson_object_set(jo, "uncompressedArtifactSize",
2040                       cson_value_new_integer((cson_int_t)t));
2041       cson_object_set(jo, "averageArtifactSize",
2042                       cson_value_new_integer((cson_int_t)db_column_int(&q, 1)));
2043       cson_object_set(jo, "maxArtifactSize",
2044                       cson_value_new_integer((cson_int_t)db_column_int(&q, 2)));
2045       db_finalize(&q);
2046       if( t/fsize < 5 ){
2047         b = 10;
2048         fsize /= 10;
2049       }else{
2050         b = 1;
2051       }
2052       a = t/fsize;
2053       sqlite3_snprintf(BufLen,zBuf, "%d:%d", a, b);
2054       SETBUF(jo, "compressionRatio");
2055     }
2056     n = db_int(0, "SELECT count(distinct mid) FROM mlink /*scan*/");
2057     cson_object_set(jo, "checkinCount", cson_value_new_integer((cson_int_t)n));
2058     n = db_int(0, "SELECT count(*) FROM filename /*scan*/");
2059     cson_object_set(jo, "fileCount", cson_value_new_integer((cson_int_t)n));
2060     n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
2061                " WHERE +tagname GLOB 'wiki-*'");
2062     cson_object_set(jo, "wikiPageCount", cson_value_new_integer((cson_int_t)n));
2063     n = db_int(0, "SELECT count(*) FROM tag  /*scan*/"
2064                " WHERE +tagname GLOB 'tkt-*'");
2065     cson_object_set(jo, "ticketCount", cson_value_new_integer((cson_int_t)n));
2066   }/*full*/
2067   n = db_int(0, "SELECT julianday('now') - (SELECT min(mtime) FROM event)"
2068                 " + 0.99");
2069   cson_object_set(jo, "ageDays", cson_value_new_integer((cson_int_t)n));
2070   cson_object_set(jo, "ageYears", cson_value_new_double(n/365.2425));
2071   sqlite3_snprintf(BufLen, zBuf, db_get("project-code",""));
2072   SETBUF(jo, "projectCode");
2073   cson_object_set(jo, "compiler", cson_value_new_string(COMPILER_NAME, strlen(COMPILER_NAME)));
2074 
2075   jv2 = cson_value_new_object();
2076   jo2 = cson_value_get_object(jv2);
2077   cson_object_set(jo, "sqlite", jv2);
2078   sqlite3_snprintf(BufLen, zBuf, "%.19s [%.10s] (%s)",
2079                    sqlite3_sourceid(), &sqlite3_sourceid()[20], sqlite3_libversion());
2080   SETBUF(jo2, "version");
2081   cson_object_set(jo2, "pageCount", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_count")));
2082   cson_object_set(jo2, "pageSize", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.page_size")));
2083   cson_object_set(jo2, "freeList", cson_value_new_integer((cson_int_t)db_int(0, "PRAGMA repository.freelist_count")));
2084   sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.encoding"));
2085   SETBUF(jo2, "encoding");
2086   sqlite3_snprintf(BufLen, zBuf, "%s", db_text(0, "PRAGMA repository.journal_mode"));
2087   cson_object_set(jo2, "journalMode", *zBuf ? cson_value_new_string(zBuf, strlen(zBuf)) : cson_value_null());
2088   return jv;
2089 #undef SETBUF
2090 }
2091 
2092 
2093 
2094 
2095 /*
2096 ** Creates a comma-separated list of command names
2097 ** taken from zPages. zPages must be an array of objects
2098 ** whose final entry MUST have a NULL name value or results
2099 ** are undefined.
2100 **
2101 ** The list is appended to pOut. The number of items (not bytes)
2102 ** appended are returned. If filterByMode is non-0 then the result
2103 ** list will contain only commands which are able to run in the
2104 ** current run mode (CLI vs. HTTP).
2105 */
json_pagedefs_to_string(JsonPageDef const * zPages,Blob * pOut,int filterByMode)2106 static int json_pagedefs_to_string(JsonPageDef const * zPages,
2107                                    Blob * pOut, int filterByMode){
2108   int i = 0;
2109   for( ; zPages->name; ++zPages, ++i ){
2110     if(filterByMode){
2111       if(g.isHTTP && zPages->runMode < 0) continue;
2112       else if(zPages->runMode > 0) continue;
2113     }
2114     blob_append(pOut, zPages->name, -1);
2115     if((zPages+1)->name){
2116       blob_append(pOut, ", ",2);
2117     }
2118   }
2119   return i;
2120 }
2121 
2122 /*
2123 ** Creates an error message using zErrPrefix and the given array of
2124 ** JSON command definitions, and sets the g.json error state to
2125 ** reflect FSL_JSON_E_MISSING_ARGS. If zErrPrefix is NULL then
2126 ** some default is used (e.g. "Try one of: "). If it is "" then
2127 ** no prefix is used.
2128 **
2129 ** The intention is to provide the user (via the response.resultText)
2130 ** a list of available commands/subcommands.
2131 **
2132 */
json_dispatch_missing_args_err(JsonPageDef const * pCommands,char const * zErrPrefix)2133 void json_dispatch_missing_args_err( JsonPageDef const * pCommands,
2134                                      char const * zErrPrefix ){
2135   Blob cmdNames = empty_blob;
2136   blob_init(&cmdNames,NULL,0);
2137   if( !zErrPrefix ) {
2138     zErrPrefix = "Try one of: ";
2139   }
2140   blob_append( &cmdNames, zErrPrefix, strlen(zErrPrefix) );
2141   json_pagedefs_to_string(pCommands, &cmdNames, 1);
2142   json_set_err(FSL_JSON_E_MISSING_ARGS, "%s",
2143                blob_str(&cmdNames));
2144   blob_reset(&cmdNames);
2145 }
2146 
json_page_dispatch_helper(JsonPageDef const * pages)2147 cson_value * json_page_dispatch_helper(JsonPageDef const * pages){
2148   JsonPageDef const * def;
2149   char const * cmd = json_command_arg(1+g.json.dispatchDepth);
2150   assert( NULL != pages );
2151   if( ! cmd ){
2152     json_dispatch_missing_args_err(pages,
2153                                    "No subcommand specified. "
2154                                    "Try one of: ");
2155     return NULL;
2156   }
2157   def = json_handler_for_name( cmd, pages );
2158   if(!def){
2159     json_set_err(FSL_JSON_E_UNKNOWN_COMMAND,
2160                  "Unknown subcommand: %s", cmd);
2161     return NULL;
2162   }
2163   else{
2164     ++g.json.dispatchDepth;
2165     return (*def->func)();
2166   }
2167 }
2168 
2169 
2170 /*
2171 ** Impl of /json/rebuild. Requires admin privileges.
2172 */
json_page_rebuild()2173 static cson_value * json_page_rebuild(){
2174   if( !g.perm.Admin ){
2175     json_set_err(FSL_JSON_E_DENIED,"Requires 'a' privileges.");
2176     return NULL;
2177   }else{
2178   /* Reminder: the db_xxx() ops "should" fail via the fossil core
2179      error handlers, which will cause a JSON error and exit(). i.e. we
2180      don't handle the errors here. TODO: confirm that all these db
2181      routine fail gracefully in JSON mode.
2182 
2183      On large repos (e.g. fossil's) this operation is likely to take
2184      longer than the client timeout, which will cause it to fail (but
2185      it's sqlite3, so it'll fail gracefully).
2186   */
2187     db_close(1);
2188     db_open_repository(g.zRepositoryName);
2189     db_begin_transaction();
2190     rebuild_db(0, 0, 0);
2191     db_end_transaction(0);
2192     return NULL;
2193   }
2194 }
2195 
2196 /*
2197 ** Impl of /json/g. Requires admin/setup rights.
2198 */
json_page_g()2199 static cson_value * json_page_g(){
2200   if(!g.perm.Admin || !g.perm.Setup){
2201     json_set_err(FSL_JSON_E_DENIED,
2202                  "Requires 'a' or 's' privileges.");
2203     return NULL;
2204   }
2205   return json_g_to_json();
2206 }
2207 
2208 /* Impl in json_login.c. */
2209 cson_value * json_page_anon_password();
2210 /* Impl in json_artifact.c. */
2211 cson_value * json_page_artifact();
2212 /* Impl in json_branch.c. */
2213 cson_value * json_page_branch();
2214 /* Impl in json_diff.c. */
2215 cson_value * json_page_diff();
2216 /* Impl in json_dir.c. */
2217 cson_value * json_page_dir();
2218 /* Impl in json_login.c. */
2219 cson_value * json_page_login();
2220 /* Impl in json_login.c. */
2221 cson_value * json_page_logout();
2222 /* Impl in json_query.c. */
2223 cson_value * json_page_query();
2224 /* Impl in json_report.c. */
2225 cson_value * json_page_report();
2226 /* Impl in json_tag.c. */
2227 cson_value * json_page_tag();
2228 /* Impl in json_user.c. */
2229 cson_value * json_page_user();
2230 /* Impl in json_config.c. */
2231 cson_value * json_page_config();
2232 /* Impl in json_finfo.c. */
2233 cson_value * json_page_finfo();
2234 /* Impl in json_status.c. */
2235 cson_value * json_page_status();
2236 
2237 /*
2238 ** Mapping of names to JSON pages/commands.  Each name is a subpath of
2239 ** /json (in CGI mode) or a subcommand of the json command in CLI mode
2240 */
2241 static const JsonPageDef JsonPageDefs[] = {
2242 /* please keep alphabetically sorted (case-insensitive) for maintenance reasons. */
2243 {"anonymousPassword", json_page_anon_password, 0},
2244 {"artifact", json_page_artifact, 0},
2245 {"branch", json_page_branch,0},
2246 {"cap", json_page_cap, 0},
2247 {"config", json_page_config, 0 },
2248 {"diff", json_page_diff, 0},
2249 {"dir", json_page_dir, 0},
2250 {"finfo", json_page_finfo, 0},
2251 {"g", json_page_g, 0},
2252 {"HAI",json_page_version,0},
2253 {"login",json_page_login,0},
2254 {"logout",json_page_logout,0},
2255 {"query",json_page_query,0},
2256 {"rebuild",json_page_rebuild,0},
2257 {"report", json_page_report, 0},
2258 {"resultCodes", json_page_resultCodes,0},
2259 {"stat",json_page_stat,0},
2260 {"status", json_page_status, 0},
2261 {"tag", json_page_tag,0},
2262 /*{"ticket", json_page_nyi,0},*/
2263 {"timeline", json_page_timeline,0},
2264 {"user",json_page_user,0},
2265 {"version",json_page_version,0},
2266 {"whoami",json_page_whoami,0},
2267 {"wiki",json_page_wiki,0},
2268 /* Last entry MUST have a NULL name. */
2269 {NULL,NULL,0}
2270 };
2271 
2272 /*
2273 ** Internal helper for json_cmd_top() and json_page_top().
2274 **
2275 ** Searches JsonPageDefs for a command with the given name. If found,
2276 ** it is used to generate and output a JSON response. If not found, it
2277 ** generates a JSON-style error response. Returns 0 on success, non-0
2278 ** on error. On error it will set g.json's error state.
2279 */
json_dispatch_root_command(char const * zCommand)2280 static int json_dispatch_root_command( char const * zCommand ){
2281   int rc = 0;
2282   cson_value * payload = NULL;
2283   JsonPageDef const * pageDef = NULL;
2284   pageDef = json_handler_for_name(zCommand,&JsonPageDefs[0]);
2285   if( ! pageDef ){
2286     rc = FSL_JSON_E_UNKNOWN_COMMAND;
2287     json_set_err( rc, "Unknown command: %s", zCommand );
2288   }else if( pageDef->runMode < 0 /*CLI only*/){
2289     rc = FSL_JSON_E_WRONG_MODE;
2290   }else if( (g.isHTTP && (pageDef->runMode < 0 /*CLI only*/))
2291             ||
2292             (!g.isHTTP && (pageDef->runMode > 0 /*HTTP only*/))
2293             ){
2294     rc = FSL_JSON_E_WRONG_MODE;
2295   }
2296   else{
2297     rc = 0;
2298     g.json.dispatchDepth = 1;
2299     payload = (*pageDef->func)();
2300   }
2301   payload = json_create_response(rc, NULL, payload);
2302   json_send_response(payload);
2303   cson_value_free(payload);
2304   return rc;
2305 }
2306 
2307 #ifdef FOSSIL_ENABLE_JSON
2308 /* dupe ifdef needed for mkindex */
2309 /*
2310 ** WEBPAGE: json
2311 **
2312 ** Pages under /json/... must be entered into JsonPageDefs.
2313 ** This function dispatches them, and is the HTTP equivalent of
2314 ** json_cmd_top().
2315 */
json_page_top(void)2316 void json_page_top(void){
2317   char const * zCommand;
2318   assert(g.json.gc.a && "json_bootstrap_early() was not called!");
2319   assert(g.json.cmd.a && "json_bootstrap_late() was not called!");
2320   zCommand = json_command_arg(1);
2321   if(!zCommand || !*zCommand){
2322     json_dispatch_missing_args_err( JsonPageDefs,
2323                                     "No command (sub-path) specified."
2324                                     " Try one of: ");
2325     return;
2326   }
2327   json_dispatch_root_command( zCommand );
2328 }
2329 #endif /* FOSSIL_ENABLE_JSON for mkindex */
2330 
2331 #ifdef FOSSIL_ENABLE_JSON
2332 /* dupe ifdef needed for mkindex */
2333 /*
2334 ** This function dispatches json commands and is the CLI equivalent of
2335 ** json_page_top().
2336 **
2337 ** COMMAND: json
2338 **
2339 ** Usage: %fossil json SUBCOMMAND ?OPTIONS?
2340 **
2341 ** In CLI mode, the -R REPO common option is supported. Due to limitations
2342 ** in the argument dispatching code, any -FLAGS must come after the final
2343 ** sub- (or subsub-) command.
2344 **
2345 ** The -json-input FILE option can be used to read JSON data and process
2346 ** it like the HTTP interface would. For example:
2347 **
2348 **   %fossil json -json-input my.json
2349 **
2350 ** The commands include:
2351 **
2352 **   anonymousPassword
2353 **   artifact
2354 **   branch
2355 **   cap
2356 **   config
2357 **   diff
2358 **   dir
2359 **   g
2360 **   login
2361 **   logout
2362 **   query
2363 **   rebuild
2364 **   report
2365 **   resultCodes
2366 **   stat
2367 **   tag
2368 **   timeline
2369 **   user
2370 **   version (alias: HAI)
2371 **   whoami
2372 **   wiki
2373 **
2374 ** Run '%fossil json' without any subcommand to see the full list (but be
2375 ** aware that some listed might not yet be fully implemented).
2376 **
2377 */
json_cmd_top(void)2378 void json_cmd_top(void){
2379   char const * cmd = NULL;
2380   int rc = 0;
2381   memset( &g.perm, 0xff, sizeof(g.perm) )
2382     /* In CLI mode fossil does not use permissions
2383        and they all default to false. We enable them
2384        here because (A) fossil doesn't use them in local
2385        mode but (B) having them set gives us one less
2386        difference in the CLI/CGI/Server-mode JSON
2387        handling.
2388     */
2389     ;
2390   json_bootstrap_early();
2391   json_bootstrap_late();
2392   if( 2 > cson_array_length_get(g.json.cmd.a) ){
2393     goto usage;
2394   }
2395 #if 0
2396   json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
2397   json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
2398 #endif
2399   cmd = json_command_arg(1);
2400   if( !cmd || !*cmd ){
2401     goto usage;
2402   }
2403   rc = json_dispatch_root_command( cmd );
2404   if(0 != rc){
2405     /* FIXME: we need a way of passing this error back
2406        up to the routine which called this callback.
2407        e.g. add g.errCode.
2408     */
2409     fossil_exit(1);
2410   }
2411   return;
2412   usage:
2413   {
2414     cson_value * payload;
2415     json_dispatch_missing_args_err( JsonPageDefs,
2416                                     "No subcommand specified."
2417                                     " Try one of: ");
2418     payload = json_create_response(0, NULL, NULL);
2419     json_send_response(payload);
2420     cson_value_free(payload);
2421     fossil_exit(1);
2422   }
2423 }
2424 #endif /* FOSSIL_ENABLE_JSON for mkindex */
2425 
2426 #endif /* FOSSIL_ENABLE_JSON */
2427