Fossil SCM
Added initial JSONP support, but lacks significant testing.
Commit
e72ae99dc2aa29b57f2c29014225c2c73178eee7
Parent
e01d49b252d9d2a…
1 file changed
+82
-24
+82
-24
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -217,10 +217,18 @@ | ||
| 217 | 217 | cson_value * root = NULL; |
| 218 | 218 | blob_rewind( pSrc ); |
| 219 | 219 | cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo ); |
| 220 | 220 | return root; |
| 221 | 221 | } |
| 222 | +/* | |
| 223 | +** Implements the cson_data_dest_f() interface and outputs the data to | |
| 224 | +** cgi_append_content(). pState is ignored. | |
| 225 | +**/ | |
| 226 | +int cson_data_dest_cgi(void * pState, void const * src, unsigned int n){ | |
| 227 | + cgi_append_content( (char const *)src, (int)n ); | |
| 228 | + return 0; | |
| 229 | +} | |
| 222 | 230 | |
| 223 | 231 | /* |
| 224 | 232 | ** Returns a string in the form FOSSIL-XXXX, where XXXX is a |
| 225 | 233 | ** left-zero-padded value of code. The returned buffer is static, and |
| 226 | 234 | ** must be copied if needed for later. The returned value will always |
| @@ -424,10 +432,46 @@ | ||
| 424 | 432 | return "text/plain"; |
| 425 | 433 | } |
| 426 | 434 | } |
| 427 | 435 | } |
| 428 | 436 | } |
| 437 | + | |
| 438 | +/* | |
| 439 | +** Sends pResponse to the output stream as the response object. This | |
| 440 | +** function does no validation of pResponse except to assert() that it | |
| 441 | +** is not NULL. The caller is responsible for ensuring that it meets | |
| 442 | +** API response envelope conventions. | |
| 443 | +** | |
| 444 | +** In CLI mode pResponse is sent to stdout immediately. In HTTP | |
| 445 | +** mode pResponse replaces any current CGI content but cgi_reply() | |
| 446 | +** is not called to flush the output. | |
| 447 | +** | |
| 448 | +** If g.json.jsonp is not NULL then the content type is set to | |
| 449 | +** application/javascript and the output is wrapped in a jsonp | |
| 450 | +** wrapper. | |
| 451 | +*/ | |
| 452 | +void json_send_response( cson_value const * pResponse ){ | |
| 453 | + assert( NULL != pResponse ); | |
| 454 | + if( g.isHTTP ){ | |
| 455 | + cgi_reset_content(); | |
| 456 | + if( g.json.jsonp ){ | |
| 457 | + cgi_printf("%s(",g.json.jsonp); | |
| 458 | + } | |
| 459 | + cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); | |
| 460 | + if( g.json.jsonp ){ | |
| 461 | + cgi_append_content(")",1); | |
| 462 | + } | |
| 463 | + }else{/*CLI mode*/ | |
| 464 | + if( g.json.jsonp ){ | |
| 465 | + fprintf(stdout,"%s(",g.json.jsonp); | |
| 466 | + } | |
| 467 | + cson_output_FILE( pResponse, stdout, &g.json.outOpt ); | |
| 468 | + if( g.json.jsonp ){ | |
| 469 | + fwrite(")\n", 2, 1, stdout); | |
| 470 | + } | |
| 471 | + } | |
| 472 | +} | |
| 429 | 473 | |
| 430 | 474 | /* |
| 431 | 475 | ** Returns the current request's JSON authentication token, or NULL if |
| 432 | 476 | ** none is found. The token's memory is owned by (or shared with) |
| 433 | 477 | ** g.json. |
| @@ -714,27 +758,35 @@ | ||
| 714 | 758 | if( once ){ |
| 715 | 759 | return; |
| 716 | 760 | }else{ |
| 717 | 761 | once = 1; |
| 718 | 762 | } |
| 763 | + g.json.jsonp = PD("jsonp",NULL); | |
| 719 | 764 | g.json.isJsonMode = 1; |
| 720 | 765 | g.json.resultCode = 0; |
| 721 | 766 | g.json.cmd.offset = -1; |
| 722 | 767 | if( !g.isHTTP && g.fullHttpReply ){ |
| 723 | 768 | /* workaround for server mode, so we see it as CGI mode. */ |
| 724 | 769 | g.isHTTP = 1; |
| 725 | 770 | } |
| 771 | + | |
| 772 | + if(!g.json.jsonp && g.json.post.o){ | |
| 773 | + g.json.jsonp = cson_string_cstr(cson_value_get_string(cson_object_get(g.json.post.o,"jsonp"))); | |
| 774 | + } | |
| 726 | 775 | if( !g.isHTTP ){ |
| 727 | 776 | g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; |
| 777 | + if(!g.json.jsonp){ | |
| 778 | + g.json.jsonp = find_option("jsonp",NULL,1); | |
| 779 | + } | |
| 728 | 780 | } |
| 729 | 781 | |
| 730 | - if(! g.json.post.v ){ | |
| 731 | - /* If cgi_init() reads POSTed JSON then it sets the content type. | |
| 732 | - If it did not then we need to set it. | |
| 733 | - */ | |
| 734 | - cgi_set_content_type(json_guess_content_type()); | |
| 735 | - } | |
| 782 | + /* FIXME: do some sanity checking on g.json.jsonp and ignore it | |
| 783 | + if it is not halfway reasonable. | |
| 784 | + */ | |
| 785 | + cgi_set_content_type(json_guess_content_type()) | |
| 786 | + /* reminder: must be done after g.json.jsonp is initialized */ | |
| 787 | + ; | |
| 736 | 788 | |
| 737 | 789 | #if defined(NDEBUG) |
| 738 | 790 | /* avoids debug messages on stderr in JSON mode */ |
| 739 | 791 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 740 | 792 | #endif |
| @@ -793,11 +845,13 @@ | ||
| 793 | 845 | cson_int_t const n = cson_value_get_integer(indentV); |
| 794 | 846 | indent = (n>0) ? (unsigned char)n : 0; |
| 795 | 847 | } |
| 796 | 848 | } |
| 797 | 849 | g.json.outOpt.indentation = indent; |
| 798 | - g.json.outOpt.addNewline = g.isHTTP ? 0 : 1; | |
| 850 | + g.json.outOpt.addNewline = g.isHTTP | |
| 851 | + ? 0 | |
| 852 | + : (g.json.jsonp ? 0 : 1); | |
| 799 | 853 | } |
| 800 | 854 | |
| 801 | 855 | if( g.isHTTP ){ |
| 802 | 856 | json_auth_token()/* will copy our auth token, if any, to fossil's |
| 803 | 857 | core, which we need before we call |
| @@ -994,12 +1048,12 @@ | ||
| 994 | 1048 | ** provide his own or may use an empty string to suppress the |
| 995 | 1049 | ** resultText property. |
| 996 | 1050 | ** |
| 997 | 1051 | */ |
| 998 | 1052 | cson_value * json_create_response( int resultCode, |
| 999 | - cson_value * payload, | |
| 1000 | - char const * pMsg ){ | |
| 1053 | + char const * pMsg, | |
| 1054 | + cson_value * payload){ | |
| 1001 | 1055 | cson_value * v = NULL; |
| 1002 | 1056 | cson_value * tmp = NULL; |
| 1003 | 1057 | cson_object * o = NULL; |
| 1004 | 1058 | int rc; |
| 1005 | 1059 | resultCode = json_dumbdown_rc(resultCode); |
| @@ -1100,29 +1154,36 @@ | ||
| 1100 | 1154 | cson_value * resp = NULL; |
| 1101 | 1155 | rc = json_dumbdown_rc(rc); |
| 1102 | 1156 | if( rc && !msg ){ |
| 1103 | 1157 | msg = json_err_str(rc); |
| 1104 | 1158 | } |
| 1105 | - resp = json_create_response(rc, NULL, msg); | |
| 1159 | + resp = json_create_response(rc, msg, NULL); | |
| 1106 | 1160 | if(!resp){ |
| 1107 | 1161 | /* about the only error case here is out-of-memory. DO NOT |
| 1108 | 1162 | call fossil_panic() here because that calls this function. |
| 1109 | 1163 | */ |
| 1110 | 1164 | fprintf(stderr, "%s: Fatal error: could not allocate " |
| 1111 | 1165 | "response object.\n", fossil_nameofexe()); |
| 1112 | 1166 | fossil_exit(1); |
| 1113 | 1167 | } |
| 1114 | 1168 | if( g.isHTTP ){ |
| 1115 | - Blob buf = empty_blob; | |
| 1116 | - cgi_reset_content(); | |
| 1117 | - cson_output_Blob( resp, &buf, &g.json.outOpt ); | |
| 1118 | - cgi_set_content(&buf); | |
| 1119 | - if( alsoOutput ){ | |
| 1120 | - cgi_reply(); | |
| 1169 | + if(alsoOutput){ | |
| 1170 | + json_send_response(resp); | |
| 1171 | + }else{ | |
| 1172 | + /* almost a duplicate of json_send_response() :( */ | |
| 1173 | + cgi_set_content_type("application/javascript"); | |
| 1174 | + cgi_reset_content(); | |
| 1175 | + if( g.json.jsonp ){ | |
| 1176 | + cgi_printf("%s(",g.json.jsonp); | |
| 1177 | + } | |
| 1178 | + cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt ); | |
| 1179 | + if( g.json.jsonp ){ | |
| 1180 | + cgi_append_content(")",1); | |
| 1181 | + } | |
| 1121 | 1182 | } |
| 1122 | 1183 | }else{ |
| 1123 | - cson_output_FILE( resp, stdout, &g.json.outOpt ); | |
| 1184 | + json_send_response(resp); | |
| 1124 | 1185 | } |
| 1125 | 1186 | cson_value_free(resp); |
| 1126 | 1187 | } |
| 1127 | 1188 | |
| 1128 | 1189 | /* |
| @@ -2348,11 +2409,10 @@ | ||
| 2348 | 2409 | ** This function dispatches them, and is the HTTP equivalent of |
| 2349 | 2410 | ** json_cmd_top(). |
| 2350 | 2411 | */ |
| 2351 | 2412 | void json_page_top(void){ |
| 2352 | 2413 | int rc = FSL_JSON_E_UNKNOWN_COMMAND; |
| 2353 | - Blob buf = empty_blob; | |
| 2354 | 2414 | char const * cmd; |
| 2355 | 2415 | cson_value * payload = NULL; |
| 2356 | 2416 | cson_value * root = NULL; |
| 2357 | 2417 | JsonPageDef const * pageDef = NULL; |
| 2358 | 2418 | json_mode_bootstrap(); |
| @@ -2369,15 +2429,13 @@ | ||
| 2369 | 2429 | payload = (*pageDef->func)(1); |
| 2370 | 2430 | } |
| 2371 | 2431 | if( g.json.resultCode ){ |
| 2372 | 2432 | json_err(g.json.resultCode, NULL, 0); |
| 2373 | 2433 | }else{ |
| 2374 | - blob_zero(&buf); | |
| 2375 | - root = json_create_response(rc, payload, NULL); | |
| 2376 | - cson_output_Blob( root, &buf, NULL ); | |
| 2434 | + root = json_create_response(rc, NULL, payload); | |
| 2435 | + json_send_response(payload); | |
| 2377 | 2436 | cson_value_free(root); |
| 2378 | - cgi_set_content(&buf)/*takes ownership of the buf memory*/; | |
| 2379 | 2437 | } |
| 2380 | 2438 | } |
| 2381 | 2439 | |
| 2382 | 2440 | /* |
| 2383 | 2441 | ** This function dispatches json commands and is the CLI equivalent of |
| @@ -2443,12 +2501,12 @@ | ||
| 2443 | 2501 | payload = (*pageDef->func)(1); |
| 2444 | 2502 | } |
| 2445 | 2503 | if( g.json.resultCode ){ |
| 2446 | 2504 | json_err(g.json.resultCode, NULL, 1); |
| 2447 | 2505 | }else{ |
| 2448 | - payload = json_create_response(rc, payload, NULL); | |
| 2449 | - cson_output_FILE( payload, stdout, &g.json.outOpt ); | |
| 2506 | + payload = json_create_response(rc, NULL, payload); | |
| 2507 | + json_send_response(payload); | |
| 2450 | 2508 | cson_value_free( payload ); |
| 2451 | 2509 | if((0 != rc) && !g.isHTTP){ |
| 2452 | 2510 | /* FIXME: we need a way of passing this error back |
| 2453 | 2511 | up to the routine which called this callback. |
| 2454 | 2512 | e.g. add g.errCode. |
| 2455 | 2513 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -217,10 +217,18 @@ | |
| 217 | cson_value * root = NULL; |
| 218 | blob_rewind( pSrc ); |
| 219 | cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo ); |
| 220 | return root; |
| 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 |
| @@ -424,10 +432,46 @@ | |
| 424 | return "text/plain"; |
| 425 | } |
| 426 | } |
| 427 | } |
| 428 | } |
| 429 | |
| 430 | /* |
| 431 | ** Returns the current request's JSON authentication token, or NULL if |
| 432 | ** none is found. The token's memory is owned by (or shared with) |
| 433 | ** g.json. |
| @@ -714,27 +758,35 @@ | |
| 714 | if( once ){ |
| 715 | return; |
| 716 | }else{ |
| 717 | once = 1; |
| 718 | } |
| 719 | g.json.isJsonMode = 1; |
| 720 | g.json.resultCode = 0; |
| 721 | g.json.cmd.offset = -1; |
| 722 | if( !g.isHTTP && g.fullHttpReply ){ |
| 723 | /* workaround for server mode, so we see it as CGI mode. */ |
| 724 | g.isHTTP = 1; |
| 725 | } |
| 726 | if( !g.isHTTP ){ |
| 727 | g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; |
| 728 | } |
| 729 | |
| 730 | if(! g.json.post.v ){ |
| 731 | /* If cgi_init() reads POSTed JSON then it sets the content type. |
| 732 | If it did not then we need to set it. |
| 733 | */ |
| 734 | cgi_set_content_type(json_guess_content_type()); |
| 735 | } |
| 736 | |
| 737 | #if defined(NDEBUG) |
| 738 | /* avoids debug messages on stderr in JSON mode */ |
| 739 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 740 | #endif |
| @@ -793,11 +845,13 @@ | |
| 793 | cson_int_t const n = cson_value_get_integer(indentV); |
| 794 | indent = (n>0) ? (unsigned char)n : 0; |
| 795 | } |
| 796 | } |
| 797 | g.json.outOpt.indentation = indent; |
| 798 | g.json.outOpt.addNewline = g.isHTTP ? 0 : 1; |
| 799 | } |
| 800 | |
| 801 | if( g.isHTTP ){ |
| 802 | json_auth_token()/* will copy our auth token, if any, to fossil's |
| 803 | core, which we need before we call |
| @@ -994,12 +1048,12 @@ | |
| 994 | ** provide his own or may use an empty string to suppress the |
| 995 | ** resultText property. |
| 996 | ** |
| 997 | */ |
| 998 | cson_value * json_create_response( int resultCode, |
| 999 | cson_value * payload, |
| 1000 | char const * pMsg ){ |
| 1001 | cson_value * v = NULL; |
| 1002 | cson_value * tmp = NULL; |
| 1003 | cson_object * o = NULL; |
| 1004 | int rc; |
| 1005 | resultCode = json_dumbdown_rc(resultCode); |
| @@ -1100,29 +1154,36 @@ | |
| 1100 | cson_value * resp = NULL; |
| 1101 | rc = json_dumbdown_rc(rc); |
| 1102 | if( rc && !msg ){ |
| 1103 | msg = json_err_str(rc); |
| 1104 | } |
| 1105 | resp = json_create_response(rc, NULL, msg); |
| 1106 | if(!resp){ |
| 1107 | /* about the only error case here is out-of-memory. DO NOT |
| 1108 | call fossil_panic() here because that calls this function. |
| 1109 | */ |
| 1110 | fprintf(stderr, "%s: Fatal error: could not allocate " |
| 1111 | "response object.\n", fossil_nameofexe()); |
| 1112 | fossil_exit(1); |
| 1113 | } |
| 1114 | if( g.isHTTP ){ |
| 1115 | Blob buf = empty_blob; |
| 1116 | cgi_reset_content(); |
| 1117 | cson_output_Blob( resp, &buf, &g.json.outOpt ); |
| 1118 | cgi_set_content(&buf); |
| 1119 | if( alsoOutput ){ |
| 1120 | cgi_reply(); |
| 1121 | } |
| 1122 | }else{ |
| 1123 | cson_output_FILE( resp, stdout, &g.json.outOpt ); |
| 1124 | } |
| 1125 | cson_value_free(resp); |
| 1126 | } |
| 1127 | |
| 1128 | /* |
| @@ -2348,11 +2409,10 @@ | |
| 2348 | ** This function dispatches them, and is the HTTP equivalent of |
| 2349 | ** json_cmd_top(). |
| 2350 | */ |
| 2351 | void json_page_top(void){ |
| 2352 | int rc = FSL_JSON_E_UNKNOWN_COMMAND; |
| 2353 | Blob buf = empty_blob; |
| 2354 | char const * cmd; |
| 2355 | cson_value * payload = NULL; |
| 2356 | cson_value * root = NULL; |
| 2357 | JsonPageDef const * pageDef = NULL; |
| 2358 | json_mode_bootstrap(); |
| @@ -2369,15 +2429,13 @@ | |
| 2369 | payload = (*pageDef->func)(1); |
| 2370 | } |
| 2371 | if( g.json.resultCode ){ |
| 2372 | json_err(g.json.resultCode, NULL, 0); |
| 2373 | }else{ |
| 2374 | blob_zero(&buf); |
| 2375 | root = json_create_response(rc, payload, NULL); |
| 2376 | cson_output_Blob( root, &buf, NULL ); |
| 2377 | cson_value_free(root); |
| 2378 | cgi_set_content(&buf)/*takes ownership of the buf memory*/; |
| 2379 | } |
| 2380 | } |
| 2381 | |
| 2382 | /* |
| 2383 | ** This function dispatches json commands and is the CLI equivalent of |
| @@ -2443,12 +2501,12 @@ | |
| 2443 | payload = (*pageDef->func)(1); |
| 2444 | } |
| 2445 | if( g.json.resultCode ){ |
| 2446 | json_err(g.json.resultCode, NULL, 1); |
| 2447 | }else{ |
| 2448 | payload = json_create_response(rc, payload, NULL); |
| 2449 | cson_output_FILE( payload, stdout, &g.json.outOpt ); |
| 2450 | cson_value_free( payload ); |
| 2451 | if((0 != rc) && !g.isHTTP){ |
| 2452 | /* FIXME: we need a way of passing this error back |
| 2453 | up to the routine which called this callback. |
| 2454 | e.g. add g.errCode. |
| 2455 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -217,10 +217,18 @@ | |
| 217 | cson_value * root = NULL; |
| 218 | blob_rewind( pSrc ); |
| 219 | cson_parse( &root, cson_data_src_Blob, pSrc, NULL, pInfo ); |
| 220 | return root; |
| 221 | } |
| 222 | /* |
| 223 | ** Implements the cson_data_dest_f() interface and outputs the data to |
| 224 | ** cgi_append_content(). pState is ignored. |
| 225 | **/ |
| 226 | int cson_data_dest_cgi(void * pState, void const * src, unsigned int n){ |
| 227 | cgi_append_content( (char const *)src, (int)n ); |
| 228 | return 0; |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | ** Returns a string in the form FOSSIL-XXXX, where XXXX is a |
| 233 | ** left-zero-padded value of code. The returned buffer is static, and |
| 234 | ** must be copied if needed for later. The returned value will always |
| @@ -424,10 +432,46 @@ | |
| 432 | return "text/plain"; |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | /* |
| 439 | ** Sends pResponse to the output stream as the response object. This |
| 440 | ** function does no validation of pResponse except to assert() that it |
| 441 | ** is not NULL. The caller is responsible for ensuring that it meets |
| 442 | ** API response envelope conventions. |
| 443 | ** |
| 444 | ** In CLI mode pResponse is sent to stdout immediately. In HTTP |
| 445 | ** mode pResponse replaces any current CGI content but cgi_reply() |
| 446 | ** is not called to flush the output. |
| 447 | ** |
| 448 | ** If g.json.jsonp is not NULL then the content type is set to |
| 449 | ** application/javascript and the output is wrapped in a jsonp |
| 450 | ** wrapper. |
| 451 | */ |
| 452 | void json_send_response( cson_value const * pResponse ){ |
| 453 | assert( NULL != pResponse ); |
| 454 | if( g.isHTTP ){ |
| 455 | cgi_reset_content(); |
| 456 | if( g.json.jsonp ){ |
| 457 | cgi_printf("%s(",g.json.jsonp); |
| 458 | } |
| 459 | cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 460 | if( g.json.jsonp ){ |
| 461 | cgi_append_content(")",1); |
| 462 | } |
| 463 | }else{/*CLI mode*/ |
| 464 | if( g.json.jsonp ){ |
| 465 | fprintf(stdout,"%s(",g.json.jsonp); |
| 466 | } |
| 467 | cson_output_FILE( pResponse, stdout, &g.json.outOpt ); |
| 468 | if( g.json.jsonp ){ |
| 469 | fwrite(")\n", 2, 1, stdout); |
| 470 | } |
| 471 | } |
| 472 | } |
| 473 | |
| 474 | /* |
| 475 | ** Returns the current request's JSON authentication token, or NULL if |
| 476 | ** none is found. The token's memory is owned by (or shared with) |
| 477 | ** g.json. |
| @@ -714,27 +758,35 @@ | |
| 758 | if( once ){ |
| 759 | return; |
| 760 | }else{ |
| 761 | once = 1; |
| 762 | } |
| 763 | g.json.jsonp = PD("jsonp",NULL); |
| 764 | g.json.isJsonMode = 1; |
| 765 | g.json.resultCode = 0; |
| 766 | g.json.cmd.offset = -1; |
| 767 | if( !g.isHTTP && g.fullHttpReply ){ |
| 768 | /* workaround for server mode, so we see it as CGI mode. */ |
| 769 | g.isHTTP = 1; |
| 770 | } |
| 771 | |
| 772 | if(!g.json.jsonp && g.json.post.o){ |
| 773 | g.json.jsonp = cson_string_cstr(cson_value_get_string(cson_object_get(g.json.post.o,"jsonp"))); |
| 774 | } |
| 775 | if( !g.isHTTP ){ |
| 776 | g.json.errorDetailParanoia = 0 /*disable error code dumb-down for CLI mode*/; |
| 777 | if(!g.json.jsonp){ |
| 778 | g.json.jsonp = find_option("jsonp",NULL,1); |
| 779 | } |
| 780 | } |
| 781 | |
| 782 | /* FIXME: do some sanity checking on g.json.jsonp and ignore it |
| 783 | if it is not halfway reasonable. |
| 784 | */ |
| 785 | cgi_set_content_type(json_guess_content_type()) |
| 786 | /* reminder: must be done after g.json.jsonp is initialized */ |
| 787 | ; |
| 788 | |
| 789 | #if defined(NDEBUG) |
| 790 | /* avoids debug messages on stderr in JSON mode */ |
| 791 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 792 | #endif |
| @@ -793,11 +845,13 @@ | |
| 845 | cson_int_t const n = cson_value_get_integer(indentV); |
| 846 | indent = (n>0) ? (unsigned char)n : 0; |
| 847 | } |
| 848 | } |
| 849 | g.json.outOpt.indentation = indent; |
| 850 | g.json.outOpt.addNewline = g.isHTTP |
| 851 | ? 0 |
| 852 | : (g.json.jsonp ? 0 : 1); |
| 853 | } |
| 854 | |
| 855 | if( g.isHTTP ){ |
| 856 | json_auth_token()/* will copy our auth token, if any, to fossil's |
| 857 | core, which we need before we call |
| @@ -994,12 +1048,12 @@ | |
| 1048 | ** provide his own or may use an empty string to suppress the |
| 1049 | ** resultText property. |
| 1050 | ** |
| 1051 | */ |
| 1052 | cson_value * json_create_response( int resultCode, |
| 1053 | char const * pMsg, |
| 1054 | cson_value * payload){ |
| 1055 | cson_value * v = NULL; |
| 1056 | cson_value * tmp = NULL; |
| 1057 | cson_object * o = NULL; |
| 1058 | int rc; |
| 1059 | resultCode = json_dumbdown_rc(resultCode); |
| @@ -1100,29 +1154,36 @@ | |
| 1154 | cson_value * resp = NULL; |
| 1155 | rc = json_dumbdown_rc(rc); |
| 1156 | if( rc && !msg ){ |
| 1157 | msg = json_err_str(rc); |
| 1158 | } |
| 1159 | resp = json_create_response(rc, msg, NULL); |
| 1160 | if(!resp){ |
| 1161 | /* about the only error case here is out-of-memory. DO NOT |
| 1162 | call fossil_panic() here because that calls this function. |
| 1163 | */ |
| 1164 | fprintf(stderr, "%s: Fatal error: could not allocate " |
| 1165 | "response object.\n", fossil_nameofexe()); |
| 1166 | fossil_exit(1); |
| 1167 | } |
| 1168 | if( g.isHTTP ){ |
| 1169 | if(alsoOutput){ |
| 1170 | json_send_response(resp); |
| 1171 | }else{ |
| 1172 | /* almost a duplicate of json_send_response() :( */ |
| 1173 | cgi_set_content_type("application/javascript"); |
| 1174 | cgi_reset_content(); |
| 1175 | if( g.json.jsonp ){ |
| 1176 | cgi_printf("%s(",g.json.jsonp); |
| 1177 | } |
| 1178 | cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 1179 | if( g.json.jsonp ){ |
| 1180 | cgi_append_content(")",1); |
| 1181 | } |
| 1182 | } |
| 1183 | }else{ |
| 1184 | json_send_response(resp); |
| 1185 | } |
| 1186 | cson_value_free(resp); |
| 1187 | } |
| 1188 | |
| 1189 | /* |
| @@ -2348,11 +2409,10 @@ | |
| 2409 | ** This function dispatches them, and is the HTTP equivalent of |
| 2410 | ** json_cmd_top(). |
| 2411 | */ |
| 2412 | void json_page_top(void){ |
| 2413 | int rc = FSL_JSON_E_UNKNOWN_COMMAND; |
| 2414 | char const * cmd; |
| 2415 | cson_value * payload = NULL; |
| 2416 | cson_value * root = NULL; |
| 2417 | JsonPageDef const * pageDef = NULL; |
| 2418 | json_mode_bootstrap(); |
| @@ -2369,15 +2429,13 @@ | |
| 2429 | payload = (*pageDef->func)(1); |
| 2430 | } |
| 2431 | if( g.json.resultCode ){ |
| 2432 | json_err(g.json.resultCode, NULL, 0); |
| 2433 | }else{ |
| 2434 | root = json_create_response(rc, NULL, payload); |
| 2435 | json_send_response(payload); |
| 2436 | cson_value_free(root); |
| 2437 | } |
| 2438 | } |
| 2439 | |
| 2440 | /* |
| 2441 | ** This function dispatches json commands and is the CLI equivalent of |
| @@ -2443,12 +2501,12 @@ | |
| 2501 | payload = (*pageDef->func)(1); |
| 2502 | } |
| 2503 | if( g.json.resultCode ){ |
| 2504 | json_err(g.json.resultCode, NULL, 1); |
| 2505 | }else{ |
| 2506 | payload = json_create_response(rc, NULL, payload); |
| 2507 | json_send_response(payload); |
| 2508 | cson_value_free( payload ); |
| 2509 | if((0 != rc) && !g.isHTTP){ |
| 2510 | /* FIXME: we need a way of passing this error back |
| 2511 | up to the routine which called this callback. |
| 2512 | e.g. add g.errCode. |
| 2513 |