Fossil

Artifact Content
Login

Artifact 6df1d80dece8968b344e4b730aae8151c7c61955:


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