Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Corrected [b2ac2183] to work with CGI directory-serving mode. Renamed the two JSON bootstrap routines to be more descriptive and made it a harmless no-op to call json_bootstrap_early() (formerly json_main_bootstrap()) multiple times in order to simplify some code. Several minor code style fixes in related code. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
e7f13b82b63a4f54171e253b12de17d0 |
| User & Date: | stephan 2020-07-21 02:47:01.849 |
Context
|
2020-07-21
| ||
| 12:52 | Trivial makeheaders patch from [https://fossil-scm.org/forum/forumpost/0fc3f6b8d8], plus a small typo fix. ... (check-in: 00ad7ef3f2 user: stephan tags: trunk) | |
| 02:47 | Corrected [b2ac2183] to work with CGI directory-serving mode. Renamed the two JSON bootstrap routines to be more descriptive and made it a harmless no-op to call json_bootstrap_early() (formerly json_main_bootstrap()) multiple times in order to simplify some code. Several minor code style fixes in related code. ... (check-in: e7f13b82b6 user: stephan tags: trunk) | |
|
2020-07-20
| ||
| 15:18 | Fixed several "Ok" -> "OK". ... (check-in: b92e460fd7 user: wyoung tags: trunk) | |
Changes
Changes to src/cgi.c.
| ︙ | ︙ | |||
956 957 958 959 960 961 962 |
*/
void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
cson_value * jv = NULL;
int rc;
CgiPostReadState state;
cson_parse_opt popt = cson_parse_opt_empty;
cson_parse_info pinfo = cson_parse_info_empty;
| | | 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 |
*/
void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
cson_value * jv = NULL;
int rc;
CgiPostReadState state;
cson_parse_opt popt = cson_parse_opt_empty;
cson_parse_info pinfo = cson_parse_info_empty;
assert(g.json.gc.a && "json_bootstrap_early() was not called!");
popt.maxDepth = 15;
state.fh = zIn;
state.len = contentLen;
state.pos = 0;
rc = cson_parse( &jv,
contentLen ? cson_data_source_FILE_n : cson_data_source_FILE,
contentLen ? (void *)&state : (void *)zIn, &popt, &pinfo );
|
| ︙ | ︙ | |||
1062 1063 1064 1065 1066 1067 1068 |
const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
const char *zPathInfo = cgi_parameter("PATH_INFO",0);
#ifdef _WIN32
const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
#endif
#ifdef FOSSIL_ENABLE_JSON
| | < | 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 |
const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
const char *zPathInfo = cgi_parameter("PATH_INFO",0);
#ifdef _WIN32
const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
#endif
#ifdef FOSSIL_ENABLE_JSON
const int noJson = P("no_json")!=0;
#endif
g.isHTTP = 1;
cgi_destination(CGI_BODY);
if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
#ifdef _WIN32
/* The Microsoft IIS web server does not define REQUEST_URI, instead it uses
** PATH_INFO for virtually the same purpose. Define REQUEST_URI the same as
|
| ︙ | ︙ | |||
1099 1100 1101 1102 1103 1104 1105 |
int i, j;
for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
cgi_set_parameter("PATH_INFO", zPathInfo);
}
#ifdef FOSSIL_ENABLE_JSON
| | > | 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 |
int i, j;
for(i=0; zRequestUri[i]==zScriptName[i] && zRequestUri[i]; i++){}
for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
cgi_set_parameter("PATH_INFO", zPathInfo);
}
#ifdef FOSSIL_ENABLE_JSON
if(noJson==0 && json_request_is_json_api(zPathInfo)){
/* We need to change some following behaviour depending on whether
** we are operating in JSON mode or not. We cannot, however, be
** certain whether we should/need to be in JSON mode until the
** PATH_INFO is set up.
*/
g.json.isJsonMode = 1;
json_bootstrap_early();
}else{
assert(!g.json.isJsonMode &&
"Internal misconfiguration of g.json.isJsonMode");
}
#endif
z = (char*)P("HTTP_COOKIE");
if( z ){
|
| ︙ | ︙ | |||
1743 1744 1745 1746 1747 1748 1749 | static char *zCmd = 0; char *z, *zToken; const char *zType = 0; int i, content_length = 0; char zLine[2000]; /* A single line of input. */ #ifdef FOSSIL_ENABLE_JSON | | | 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 |
static char *zCmd = 0;
char *z, *zToken;
const char *zType = 0;
int i, content_length = 0;
char zLine[2000]; /* A single line of input. */
#ifdef FOSSIL_ENABLE_JSON
if( nCycles==0 ){ json_bootstrap_early(); }
#endif
if( zIpAddr ){
if( nCycles==0 ){
cgi_setenv("REMOTE_ADDR", zIpAddr);
g.zIpAddr = mprintf("%s", zIpAddr);
}
}else{
|
| ︙ | ︙ |
Changes to src/db.c.
| ︙ | ︙ | |||
75 76 77 78 79 80 81 |
static void db_err(const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
| | | | 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
static void db_err(const char *zFormat, ...){
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode!=0 ){
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
json_bootstrap_early();
json_err( 0, z, 1 );
}
else
#endif /* FOSSIL_ENABLE_JSON */
if( g.xferPanic && g.cgiOutput==1 ){
cgi_reset_content();
@ error Database\serror:\s%F(z)
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
53 54 55 56 57 58 59 | "resultText" /*resultText*/, "timestamp" /*timestamp*/ }; /* ** Given the current request path string, this function returns true ** if it refers to a JSON API path. i.e. if (1) it starts with /json | | | > | | | | 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
"resultText" /*resultText*/,
"timestamp" /*timestamp*/
};
/*
** Given the current request path string, this function returns true
** if it refers to a JSON API path. i.e. if (1) it starts with /json
** or (2) g.zCmdName is "server" or "cgi" and the path starts with
** /somereponame/json. Specifically, it returns 1 in the former case
** and 2 for the latter.
*/
int json_request_is_json_api(const char * zPathInfo){
int rc = 0;
if(zPathInfo==0){
rc = 0;
}else if(0==strncmp("/json",zPathInfo,5)
&& (zPathInfo[5]==0 || zPathInfo[5]=='/')){
rc = 1;
}else if(g.zCmdName!=0 && (0==strcmp("server",g.zCmdName)
|| 0==strcmp("cgi",g.zCmdName)) ){
/* When running in server/cgi "directory" mode, zPathInfo is
** prefixed with the repository's name, so in order to determine
** whether or not we're really running in json mode we have to try
** a bit harder. Problem reported here:
** https://fossil-scm.org/forum/forumpost/e4953666d6
*/
ReCompiled * pReg = 0;
const char * zErr = re_compile(&pReg, "^/[^/]+/json(/.*)?", 0);
assert(zErr==0 && "Regex compilation failed?");
if(zErr==0 &&
re_match(pReg, (const unsigned char *)zPathInfo, -1)){
|
| ︙ | ︙ | |||
685 686 687 688 689 690 691 |
** Special case: if g.useLocalauth is true (i.e. the --localauth flag
** was used to start the fossil server instance) and the current
** connection is "local", any authToken provided by the user is
** ignored and no new token is created: localauth mode trumps the
** authToken.
*/
cson_value * json_auth_token(){
| | | 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 |
** Special case: if g.useLocalauth is true (i.e. the --localauth flag
** was used to start the fossil server instance) and the current
** connection is "local", any authToken provided by the user is
** ignored and no new token is created: localauth mode trumps the
** authToken.
*/
cson_value * json_auth_token(){
assert(g.json.gc.a && "json_bootstrap_early() was not called!");
if( g.json.authToken==0 && g.noPswd==0
/* g.noPswd!=0 means the user was logged in via a local
connection using --localauth. */
){
/* Try to get an authorization token from GET parameter, POSTed
JSON, or fossil cookie (in that order). */
g.json.authToken = json_getenv(FossilJsonKeys.authToken);
|
| ︙ | ︙ | |||
738 739 740 741 742 743 744 745 746 |
** caller.
*/
cson_value * json_req_payload_get(char const *pKey){
return g.json.reqPayload.o
? cson_object_get(g.json.reqPayload.o,pKey)
: NULL;
}
/*
| > | | | > > > | > > | > | | > | < | < | < | 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 |
** caller.
*/
cson_value * json_req_payload_get(char const *pKey){
return g.json.reqPayload.o
? cson_object_get(g.json.reqPayload.o,pKey)
: NULL;
}
/*
** Returns non-zero if the json_bootstrap_early() function has already
** been called. In general, this function should be used sparingly,
** e.g. from low-level support functions like fossil_warning() where
** there is genuine uncertainty about whether (or not) the JSON setup
** has already been called.
*/
int json_is_bootstrapped_early(){
return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
}
/*
** Initializes some JSON bits which need to be initialized relatively
** early on. It should be called by any routine which might need to
** call into JSON relatively early on in the init process.
** Specifically, early on in cgi_init() and json_cmd_top(), but also
** from any error reporting routines which might be triggered (early
** on in those functions).
**
** Initializes g.json.gc and g.json.param. This code does not (and
** must not) rely on any of the fossil environment having been set
** up. e.g. it must not use cgi_parameter() and friends because this
** must be called before those data are initialized.
**
** If called multiple times, calls after the first are a no-op.
*/
void json_bootstrap_early(){
cson_value * v;
if(g.json.gc.v!=NULL){
/* Avoid multiple bootstrappings. */
return;
}
g.json.timerId = fossil_timer_start();
/* g.json.gc is our "garbage collector" - where we put JSON values
which need a long lifetime but don't have a logical parent to put
them in. */
v = cson_value_new_array();
g.json.gc.v = v;
assert(0 != g.json.gc.v);
g.json.gc.a = cson_value_get_array(v);
assert(0 != g.json.gc.a);
cson_value_add_reference(v)
/* Needed to allow us to include this value in other JSON
containers without transferring ownership to those containers.
All other persistent g.json.XXX.v values get appended to
g.json.gc.a, and therefore already have a live reference
for this purpose. */
;
/*
g.json.param holds the JSONized counterpart of fossil's
cgi_parameter_xxx() family of data. We store them as JSON, as
opposed to using fossil's data directly, because we can retain
full type information for data this way (as opposed to it always
|
| ︙ | ︙ | |||
826 827 828 829 830 831 832 |
** for consistency with how json_err() works.
*/
void json_warn( int code, char const * fmt, ... ){
cson_object * obj = NULL;
assert( (code>FSL_JSON_W_START)
&& (code<FSL_JSON_W_END)
&& "Invalid warning code.");
| | | 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 |
** for consistency with how json_err() works.
*/
void json_warn( int code, char const * fmt, ... ){
cson_object * obj = NULL;
assert( (code>FSL_JSON_W_START)
&& (code<FSL_JSON_W_END)
&& "Invalid warning code.");
assert(g.json.gc.a && "json_bootstrap_early() was not called!");
if(!g.json.warnings){
g.json.warnings = cson_new_array();
assert((NULL != g.json.warnings) && "Alloc error.");
json_gc_add("$WARNINGS",cson_array_value(g.json.warnings));
}
obj = cson_new_object();
cson_array_append(g.json.warnings, cson_object_value(obj));
|
| ︙ | ︙ | |||
973 974 975 976 977 978 979 | ** tested this) die with an error if an auth cookie is malformed. ** ** This must be called by the top-level JSON command dispatching code ** before they do any work. ** ** This must only be called once, or an assertion may be triggered. */ | | | | | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
** tested this) die with an error if an auth cookie is malformed.
**
** This must be called by the top-level JSON command dispatching code
** before they do any work.
**
** This must only be called once, or an assertion may be triggered.
*/
void json_bootstrap_late(){
static char once = 0 /* guard against multiple runs */;
char const * zPath = P("PATH_INFO");
assert(g.json.gc.a && "json_bootstrap_early() was not called!");
assert( (0==once) && "json_bootstrap_late() called too many times!");
if( once ){
return;
}else{
once = 1;
}
assert(g.json.isJsonMode
&& "g.json.isJsonMode should have been set up by now.");
|
| ︙ | ︙ | |||
1156 1157 1158 1159 1160 1161 1162 |
**
** Note that CLI options are not included in the command path. Use
** find_option() to get those.
**
*/
char const * json_command_arg(unsigned short ndx){
cson_array * ar = g.json.cmd.a;
| | | 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 |
**
** Note that CLI options are not included in the command path. Use
** find_option() to get those.
**
*/
char const * json_command_arg(unsigned short ndx){
cson_array * ar = g.json.cmd.a;
assert((NULL!=ar) && "Internal error. Was json_bootstrap_late() called?");
assert((g.argc>1) && "Internal error - we never should have gotten this far.");
if( g.json.cmd.offset < 0 ){
/* first-time setup. */
short i = 0;
#define NEXT cson_string_cstr( \
cson_value_get_string( \
cson_array_get(ar,i) \
|
| ︙ | ︙ | |||
2303 2304 2305 2306 2307 2308 2309 |
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){
char const * zCommand;
| | | | 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 |
**
** Pages under /json/... must be entered into JsonPageDefs.
** This function dispatches them, and is the HTTP equivalent of
** json_cmd_top().
*/
void json_page_top(void){
char const * zCommand;
assert(g.json.gc.a && "json_bootstrap_early() was not called!");
assert(g.json.cmd.a && "json_bootstrap_late() was not called!");
zCommand = json_command_arg(1);
if(!zCommand || !*zCommand){
json_dispatch_missing_args_err( JsonPageDefs,
"No command (sub-path) specified."
" Try one of: ");
return;
}
|
| ︙ | ︙ | |||
2375 2376 2377 2378 2379 2380 2381 |
and they all default to false. We enable them
here because (A) fossil doesn't use them in local
mode but (B) having them set gives us one less
difference in the CLI/CGI/Server-mode JSON
handling.
*/
;
| | | | 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 |
and they all default to false. We enable them
here because (A) fossil doesn't use them in local
mode but (B) having them set gives us one less
difference in the CLI/CGI/Server-mode JSON
handling.
*/
;
json_bootstrap_early();
json_bootstrap_late();
if( 2 > cson_array_length_get(g.json.cmd.a) ){
goto usage;
}
#if 0
json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing again.");
#endif
|
| ︙ | ︙ |
Changes to src/json_login.c.
| ︙ | ︙ | |||
181 182 183 184 185 186 187 |
/*
** Impl of /json/logout.
**
*/
cson_value * json_page_logout(){
cson_value const *token = g.json.authToken;
| | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
/*
** Impl of /json/logout.
**
*/
cson_value * json_page_logout(){
cson_value const *token = g.json.authToken;
/* Remember that json_bootstrap_late() replaces the login cookie
with the JSON auth token if the request contains it. If the
request is missing the auth token then this will fetch fossil's
original cookie. Either way, it's what we want :).
We require the auth token to avoid someone maliciously
trying to log someone else out (not 100% sure if that
would be possible, given fossil's hardened cookie, but
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
1577 1578 1579 1580 1581 1582 1583 | ** Ensure that JSON mode is set up if we're visiting /json, to allow ** us to customize some following behaviour (error handling and only ** process JSON-mode POST data if we're actually in a /json ** page). This is normally set up before this routine is called, but ** it looks like the ssh_request_loop() approach to dispatching ** might bypass that. */ | | > | 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 |
** Ensure that JSON mode is set up if we're visiting /json, to allow
** us to customize some following behaviour (error handling and only
** process JSON-mode POST data if we're actually in a /json
** page). This is normally set up before this routine is called, but
** it looks like the ssh_request_loop() approach to dispatching
** might bypass that.
*/
if( g.json.isJsonMode==0 && json_request_is_json_api(zPathInfo)!=0 ){
g.json.isJsonMode = 1;
json_bootstrap_early();
}
#endif
/* If the repository has not been opened already, then find the
** repository based on the first element of PATH_INFO and open it.
*/
if( !g.repositoryOpen ){
char *zRepo; /* Candidate repository name */
|
| ︙ | ︙ | |||
1855 1856 1857 1858 1859 1860 1861 |
** Disabled by stephan when running in JSON mode because this
** particular parameter name is very common and i have had no end
** of grief with this handling. The JSON API never relies on the
** handling below, and by disabling it in JSON mode I can remove
** lots of special-case handling in several JSON handlers.
*/
#ifdef FOSSIL_ENABLE_JSON
| | | | 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 |
** Disabled by stephan when running in JSON mode because this
** particular parameter name is very common and i have had no end
** of grief with this handling. The JSON API never relies on the
** handling below, and by disabling it in JSON mode I can remove
** lots of special-case handling in several JSON handlers.
*/
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode==0){
#endif
dehttpize(g.zExtra);
cgi_set_parameter_nocopy("name", g.zExtra, 1);
#ifdef FOSSIL_ENABLE_JSON
}
#endif
}
/* Locate the method specified by the path and execute the function
** that implements that method.
*/
if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
&& dispatch_alias(g.zPath-1, &pCmd)
){
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode!=0){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
}else
#endif
{
#ifdef FOSSIL_ENABLE_TH1_HOOKS
int rc;
if( !g.fNoThHook ){
|
| ︙ | ︙ | |||
1899 1900 1901 1902 1903 1904 1905 |
Th_WebpageNotify(g.zPath, 0);
}
}
#endif
}
}else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
#ifdef FOSSIL_ENABLE_JSON
| | | > | | 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 |
Th_WebpageNotify(g.zPath, 0);
}
}
#endif
}
}else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode!=0){
json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
}else
#endif
{
@ <h1>Server Configuration Error</h1>
@ <p>The database schema on the server is out-of-date. Please ask
@ the administrator to run <b>fossil rebuild</b>.</p>
}
}else{
#ifdef FOSSIL_ENABLE_JSON
static int jsonOnce = 0;
if( jsonOnce==0 && g.json.isJsonMode!=0 ){
assert(json_is_bootstrapped_early());
json_bootstrap_late();
jsonOnce = 1;
}
#endif
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
cgi_decode_post_parameters();
}
if( g.fCgiTrace ){
|
| ︙ | ︙ |
Changes to src/printf.c.
| ︙ | ︙ | |||
1073 1074 1075 1076 1077 1078 1079 |
static int mainInFatalError = 0;
/*
** Write error message output
*/
static int fossil_print_error(int rc, const char *z){
#ifdef FOSSIL_ENABLE_JSON
| | | | 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 |
static int mainInFatalError = 0;
/*
** Write error message output
*/
static int fossil_print_error(int rc, const char *z){
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode!=0 ){
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
assert(json_is_bootstrapped_early());
json_err( 0, z, 1 );
if( g.isHTTP && !g.json.preserveRc ){
rc = 0 /* avoid HTTP 500 */;
}
if( g.cgiOutput==1 ){
g.cgiOutput = 2;
cgi_reply();
|
| ︙ | ︙ | |||
1199 1200 1201 1202 1203 1204 1205 |
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("warning: %s", z);
#ifdef FOSSIL_ENABLE_JSON
| | | | 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("warning: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode!=0 ){
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
assert(json_is_bootstrapped_early());
json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
}else
#endif
{
if( g.cgiOutput==1 ){
etag_cancel();
cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
|
| ︙ | ︙ |