Fossil SCM

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.

stephan 2020-07-21 02:47 trunk
Commit e7f13b82b63a4f54171e253b12de17d0de776576db0c6d7c632073e025fb697c
+5 -5
--- src/cgi.c
+++ src/cgi.c
@@ -958,11 +958,11 @@
958958
cson_value * jv = NULL;
959959
int rc;
960960
CgiPostReadState state;
961961
cson_parse_opt popt = cson_parse_opt_empty;
962962
cson_parse_info pinfo = cson_parse_info_empty;
963
- assert(g.json.gc.a && "json_main_bootstrap() was not called!");
963
+ assert(g.json.gc.a && "json_bootstrap_early() was not called!");
964964
popt.maxDepth = 15;
965965
state.fh = zIn;
966966
state.len = contentLen;
967967
state.pos = 0;
968968
rc = cson_parse( &jv,
@@ -1064,12 +1064,11 @@
10641064
#ifdef _WIN32
10651065
const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
10661066
#endif
10671067
10681068
#ifdef FOSSIL_ENABLE_JSON
1069
- int noJson = P("no_json")!=0;
1070
- if( noJson==0 ){ json_main_bootstrap(); }
1069
+ const int noJson = P("no_json")!=0;
10711070
#endif
10721071
g.isHTTP = 1;
10731072
cgi_destination(CGI_BODY);
10741073
if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
10751074
#ifdef _WIN32
@@ -1101,17 +1100,18 @@
11011100
for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
11021101
zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
11031102
cgi_set_parameter("PATH_INFO", zPathInfo);
11041103
}
11051104
#ifdef FOSSIL_ENABLE_JSON
1106
- if(json_request_is_json_api(zPathInfo)){
1105
+ if(noJson==0 && json_request_is_json_api(zPathInfo)){
11071106
/* We need to change some following behaviour depending on whether
11081107
** we are operating in JSON mode or not. We cannot, however, be
11091108
** certain whether we should/need to be in JSON mode until the
11101109
** PATH_INFO is set up.
11111110
*/
11121111
g.json.isJsonMode = 1;
1112
+ json_bootstrap_early();
11131113
}else{
11141114
assert(!g.json.isJsonMode &&
11151115
"Internal misconfiguration of g.json.isJsonMode");
11161116
}
11171117
#endif
@@ -1745,11 +1745,11 @@
17451745
const char *zType = 0;
17461746
int i, content_length = 0;
17471747
char zLine[2000]; /* A single line of input. */
17481748
17491749
#ifdef FOSSIL_ENABLE_JSON
1750
- if( nCycles==0 ){ json_main_bootstrap(); }
1750
+ if( nCycles==0 ){ json_bootstrap_early(); }
17511751
#endif
17521752
if( zIpAddr ){
17531753
if( nCycles==0 ){
17541754
cgi_setenv("REMOTE_ADDR", zIpAddr);
17551755
g.zIpAddr = mprintf("%s", zIpAddr);
17561756
--- src/cgi.c
+++ src/cgi.c
@@ -958,11 +958,11 @@
958 cson_value * jv = NULL;
959 int rc;
960 CgiPostReadState state;
961 cson_parse_opt popt = cson_parse_opt_empty;
962 cson_parse_info pinfo = cson_parse_info_empty;
963 assert(g.json.gc.a && "json_main_bootstrap() was not called!");
964 popt.maxDepth = 15;
965 state.fh = zIn;
966 state.len = contentLen;
967 state.pos = 0;
968 rc = cson_parse( &jv,
@@ -1064,12 +1064,11 @@
1064 #ifdef _WIN32
1065 const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
1066 #endif
1067
1068 #ifdef FOSSIL_ENABLE_JSON
1069 int noJson = P("no_json")!=0;
1070 if( noJson==0 ){ json_main_bootstrap(); }
1071 #endif
1072 g.isHTTP = 1;
1073 cgi_destination(CGI_BODY);
1074 if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
1075 #ifdef _WIN32
@@ -1101,17 +1100,18 @@
1101 for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
1102 zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
1103 cgi_set_parameter("PATH_INFO", zPathInfo);
1104 }
1105 #ifdef FOSSIL_ENABLE_JSON
1106 if(json_request_is_json_api(zPathInfo)){
1107 /* We need to change some following behaviour depending on whether
1108 ** we are operating in JSON mode or not. We cannot, however, be
1109 ** certain whether we should/need to be in JSON mode until the
1110 ** PATH_INFO is set up.
1111 */
1112 g.json.isJsonMode = 1;
 
1113 }else{
1114 assert(!g.json.isJsonMode &&
1115 "Internal misconfiguration of g.json.isJsonMode");
1116 }
1117 #endif
@@ -1745,11 +1745,11 @@
1745 const char *zType = 0;
1746 int i, content_length = 0;
1747 char zLine[2000]; /* A single line of input. */
1748
1749 #ifdef FOSSIL_ENABLE_JSON
1750 if( nCycles==0 ){ json_main_bootstrap(); }
1751 #endif
1752 if( zIpAddr ){
1753 if( nCycles==0 ){
1754 cgi_setenv("REMOTE_ADDR", zIpAddr);
1755 g.zIpAddr = mprintf("%s", zIpAddr);
1756
--- src/cgi.c
+++ src/cgi.c
@@ -958,11 +958,11 @@
958 cson_value * jv = NULL;
959 int rc;
960 CgiPostReadState state;
961 cson_parse_opt popt = cson_parse_opt_empty;
962 cson_parse_info pinfo = cson_parse_info_empty;
963 assert(g.json.gc.a && "json_bootstrap_early() was not called!");
964 popt.maxDepth = 15;
965 state.fh = zIn;
966 state.len = contentLen;
967 state.pos = 0;
968 rc = cson_parse( &jv,
@@ -1064,12 +1064,11 @@
1064 #ifdef _WIN32
1065 const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
1066 #endif
1067
1068 #ifdef FOSSIL_ENABLE_JSON
1069 const int noJson = P("no_json")!=0;
 
1070 #endif
1071 g.isHTTP = 1;
1072 cgi_destination(CGI_BODY);
1073 if( zScriptName==0 ) malformed_request("missing SCRIPT_NAME");
1074 #ifdef _WIN32
@@ -1101,17 +1100,18 @@
1100 for(j=i; zRequestUri[j] && zRequestUri[j]!='?'; j++){}
1101 zPathInfo = mprintf("%.*s", j-i, zRequestUri+i);
1102 cgi_set_parameter("PATH_INFO", zPathInfo);
1103 }
1104 #ifdef FOSSIL_ENABLE_JSON
1105 if(noJson==0 && json_request_is_json_api(zPathInfo)){
1106 /* We need to change some following behaviour depending on whether
1107 ** we are operating in JSON mode or not. We cannot, however, be
1108 ** certain whether we should/need to be in JSON mode until the
1109 ** PATH_INFO is set up.
1110 */
1111 g.json.isJsonMode = 1;
1112 json_bootstrap_early();
1113 }else{
1114 assert(!g.json.isJsonMode &&
1115 "Internal misconfiguration of g.json.isJsonMode");
1116 }
1117 #endif
@@ -1745,11 +1745,11 @@
1745 const char *zType = 0;
1746 int i, content_length = 0;
1747 char zLine[2000]; /* A single line of input. */
1748
1749 #ifdef FOSSIL_ENABLE_JSON
1750 if( nCycles==0 ){ json_bootstrap_early(); }
1751 #endif
1752 if( zIpAddr ){
1753 if( nCycles==0 ){
1754 cgi_setenv("REMOTE_ADDR", zIpAddr);
1755 g.zIpAddr = mprintf("%s", zIpAddr);
1756
+2 -2
--- src/db.c
+++ src/db.c
@@ -77,17 +77,17 @@
7777
char *z;
7878
va_start(ap, zFormat);
7979
z = vmprintf(zFormat, ap);
8080
va_end(ap);
8181
#ifdef FOSSIL_ENABLE_JSON
82
- if( g.json.isJsonMode ){
82
+ if( g.json.isJsonMode!=0 ){
8383
/*
8484
** Avoid calling into the JSON support subsystem if it
8585
** has not yet been initialized, e.g. early SQLite log
8686
** messages, etc.
8787
*/
88
- if( !json_is_main_boostrapped() ) json_main_bootstrap();
88
+ json_bootstrap_early();
8989
json_err( 0, z, 1 );
9090
}
9191
else
9292
#endif /* FOSSIL_ENABLE_JSON */
9393
if( g.xferPanic && g.cgiOutput==1 ){
9494
--- src/db.c
+++ src/db.c
@@ -77,17 +77,17 @@
77 char *z;
78 va_start(ap, zFormat);
79 z = vmprintf(zFormat, ap);
80 va_end(ap);
81 #ifdef FOSSIL_ENABLE_JSON
82 if( g.json.isJsonMode ){
83 /*
84 ** Avoid calling into the JSON support subsystem if it
85 ** has not yet been initialized, e.g. early SQLite log
86 ** messages, etc.
87 */
88 if( !json_is_main_boostrapped() ) json_main_bootstrap();
89 json_err( 0, z, 1 );
90 }
91 else
92 #endif /* FOSSIL_ENABLE_JSON */
93 if( g.xferPanic && g.cgiOutput==1 ){
94
--- src/db.c
+++ src/db.c
@@ -77,17 +77,17 @@
77 char *z;
78 va_start(ap, zFormat);
79 z = vmprintf(zFormat, ap);
80 va_end(ap);
81 #ifdef FOSSIL_ENABLE_JSON
82 if( g.json.isJsonMode!=0 ){
83 /*
84 ** Avoid calling into the JSON support subsystem if it
85 ** has not yet been initialized, e.g. early SQLite log
86 ** messages, etc.
87 */
88 json_bootstrap_early();
89 json_err( 0, z, 1 );
90 }
91 else
92 #endif /* FOSSIL_ENABLE_JSON */
93 if( g.xferPanic && g.cgiOutput==1 ){
94
+33 -27
--- src/json.c
+++ src/json.c
@@ -55,11 +55,11 @@
5555
};
5656
5757
/*
5858
** Given the current request path string, this function returns true
5959
** if it refers to a JSON API path. i.e. if (1) it starts with /json
60
-** or (2) g.zCmdName is "server" and the path starts with
60
+** or (2) g.zCmdName is "server" or "cgi" and the path starts with
6161
** /somereponame/json. Specifically, it returns 1 in the former case
6262
** and 2 for the latter.
6363
*/
6464
int json_request_is_json_api(const char * zPathInfo){
6565
int rc = 0;
@@ -66,15 +66,16 @@
6666
if(zPathInfo==0){
6767
rc = 0;
6868
}else if(0==strncmp("/json",zPathInfo,5)
6969
&& (zPathInfo[5]==0 || zPathInfo[5]=='/')){
7070
rc = 1;
71
- }else if(g.zCmdName!=0 && 0==strcmp("server",g.zCmdName)){
72
- /* When running in server "directory" mode, zPathInfo is
71
+ }else if(g.zCmdName!=0 && (0==strcmp("server",g.zCmdName)
72
+ || 0==strcmp("cgi",g.zCmdName)) ){
73
+ /* When running in server/cgi "directory" mode, zPathInfo is
7374
** prefixed with the repository's name, so in order to determine
74
- ** whether or not we're really running in json mode we have to
75
- ** try a bit harder. Problem reported here:
75
+ ** whether or not we're really running in json mode we have to try
76
+ ** a bit harder. Problem reported here:
7677
** https://fossil-scm.org/forum/forumpost/e4953666d6
7778
*/
7879
ReCompiled * pReg = 0;
7980
const char * zErr = re_compile(&pReg, "^/[^/]+/json(/.*)?", 0);
8081
assert(zErr==0 && "Regex compilation failed?");
@@ -687,11 +688,11 @@
687688
** connection is "local", any authToken provided by the user is
688689
** ignored and no new token is created: localauth mode trumps the
689690
** authToken.
690691
*/
691692
cson_value * json_auth_token(){
692
- assert(g.json.gc.a && "json_main_bootstrap() was not called!");
693
+ assert(g.json.gc.a && "json_bootstrap_early() was not called!");
693694
if( g.json.authToken==0 && g.noPswd==0
694695
/* g.noPswd!=0 means the user was logged in via a local
695696
connection using --localauth. */
696697
){
697698
/* Try to get an authorization token from GET parameter, POSTed
@@ -740,43 +741,49 @@
740741
cson_value * json_req_payload_get(char const *pKey){
741742
return g.json.reqPayload.o
742743
? cson_object_get(g.json.reqPayload.o,pKey)
743744
: NULL;
744745
}
746
+
745747
746748
/*
747
-** Returns non-zero if the json_main_bootstrap() function has already
749
+** Returns non-zero if the json_bootstrap_early() function has already
748750
** been called. In general, this function should be used sparingly,
749751
** e.g. from low-level support functions like fossil_warning() where
750752
** there is genuine uncertainty about whether (or not) the JSON setup
751753
** has already been called.
752754
*/
753
-int json_is_main_boostrapped(){
755
+int json_is_bootstrapped_early(){
754756
return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
755757
}
756758
757759
/*
758760
** Initializes some JSON bits which need to be initialized relatively
759
-** early on. It should only be called from cgi_init() or
760
-** json_cmd_top() (early on in those functions).
761
+** early on. It should be called by any routine which might need to
762
+** call into JSON relatively early on in the init process.
763
+** Specifically, early on in cgi_init() and json_cmd_top(), but also
764
+** from any error reporting routines which might be triggered (early
765
+** on in those functions).
761766
**
762767
** Initializes g.json.gc and g.json.param. This code does not (and
763768
** must not) rely on any of the fossil environment having been set
764769
** up. e.g. it must not use cgi_parameter() and friends because this
765770
** must be called before those data are initialized.
771
+**
772
+** If called multiple times, calls after the first are a no-op.
766773
*/
767
-void json_main_bootstrap(){
774
+void json_bootstrap_early(){
768775
cson_value * v;
769
- assert( (NULL == g.json.gc.v) &&
770
- "json_main_bootstrap() was called twice!" );
771776
777
+ if(g.json.gc.v!=NULL){
778
+ /* Avoid multiple bootstrappings. */
779
+ return;
780
+ }
772781
g.json.timerId = fossil_timer_start();
773
-
774782
/* g.json.gc is our "garbage collector" - where we put JSON values
775783
which need a long lifetime but don't have a logical parent to put
776
- them in.
777
- */
784
+ them in. */
778785
v = cson_value_new_array();
779786
g.json.gc.v = v;
780787
assert(0 != g.json.gc.v);
781788
g.json.gc.a = cson_value_get_array(v);
782789
assert(0 != g.json.gc.a);
@@ -783,12 +790,11 @@
783790
cson_value_add_reference(v)
784791
/* Needed to allow us to include this value in other JSON
785792
containers without transferring ownership to those containers.
786793
All other persistent g.json.XXX.v values get appended to
787794
g.json.gc.a, and therefore already have a live reference
788
- for this purpose.
789
- */
795
+ for this purpose. */
790796
;
791797
792798
/*
793799
g.json.param holds the JSONized counterpart of fossil's
794800
cgi_parameter_xxx() family of data. We store them as JSON, as
@@ -828,11 +834,11 @@
828834
void json_warn( int code, char const * fmt, ... ){
829835
cson_object * obj = NULL;
830836
assert( (code>FSL_JSON_W_START)
831837
&& (code<FSL_JSON_W_END)
832838
&& "Invalid warning code.");
833
- assert(g.json.gc.a && "json_main_bootstrap() was not called!");
839
+ assert(g.json.gc.a && "json_bootstrap_early() was not called!");
834840
if(!g.json.warnings){
835841
g.json.warnings = cson_new_array();
836842
assert((NULL != g.json.warnings) && "Alloc error.");
837843
json_gc_add("$WARNINGS",cson_array_value(g.json.warnings));
838844
}
@@ -975,15 +981,15 @@
975981
** This must be called by the top-level JSON command dispatching code
976982
** before they do any work.
977983
**
978984
** This must only be called once, or an assertion may be triggered.
979985
*/
980
-void json_mode_bootstrap(){
986
+void json_bootstrap_late(){
981987
static char once = 0 /* guard against multiple runs */;
982988
char const * zPath = P("PATH_INFO");
983
- assert(g.json.gc.a && "json_main_bootstrap() was not called!");
984
- assert( (0==once) && "json_mode_bootstrap() called too many times!");
989
+ assert(g.json.gc.a && "json_bootstrap_early() was not called!");
990
+ assert( (0==once) && "json_bootstrap_late() called too many times!");
985991
if( once ){
986992
return;
987993
}else{
988994
once = 1;
989995
}
@@ -1158,11 +1164,11 @@
11581164
** find_option() to get those.
11591165
**
11601166
*/
11611167
char const * json_command_arg(unsigned short ndx){
11621168
cson_array * ar = g.json.cmd.a;
1163
- assert((NULL!=ar) && "Internal error. Was json_mode_bootstrap() called?");
1169
+ assert((NULL!=ar) && "Internal error. Was json_bootstrap_late() called?");
11641170
assert((g.argc>1) && "Internal error - we never should have gotten this far.");
11651171
if( g.json.cmd.offset < 0 ){
11661172
/* first-time setup. */
11671173
short i = 0;
11681174
#define NEXT cson_string_cstr( \
@@ -2305,12 +2311,12 @@
23052311
** This function dispatches them, and is the HTTP equivalent of
23062312
** json_cmd_top().
23072313
*/
23082314
void json_page_top(void){
23092315
char const * zCommand;
2310
- assert(g.json.gc.a && "json_main_bootstrap() was not called!");
2311
- assert(g.json.cmd.a && "json_mode_bootstrap() was not called!");
2316
+ assert(g.json.gc.a && "json_bootstrap_early() was not called!");
2317
+ assert(g.json.cmd.a && "json_bootstrap_late() was not called!");
23122318
zCommand = json_command_arg(1);
23132319
if(!zCommand || !*zCommand){
23142320
json_dispatch_missing_args_err( JsonPageDefs,
23152321
"No command (sub-path) specified."
23162322
" Try one of: ");
@@ -2377,12 +2383,12 @@
23772383
mode but (B) having them set gives us one less
23782384
difference in the CLI/CGI/Server-mode JSON
23792385
handling.
23802386
*/
23812387
;
2382
- json_main_bootstrap();
2383
- json_mode_bootstrap();
2388
+ json_bootstrap_early();
2389
+ json_bootstrap_late();
23842390
if( 2 > cson_array_length_get(g.json.cmd.a) ){
23852391
goto usage;
23862392
}
23872393
#if 0
23882394
json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
23892395
--- src/json.c
+++ src/json.c
@@ -55,11 +55,11 @@
55 };
56
57 /*
58 ** Given the current request path string, this function returns true
59 ** if it refers to a JSON API path. i.e. if (1) it starts with /json
60 ** or (2) g.zCmdName is "server" and the path starts with
61 ** /somereponame/json. Specifically, it returns 1 in the former case
62 ** and 2 for the latter.
63 */
64 int json_request_is_json_api(const char * zPathInfo){
65 int rc = 0;
@@ -66,15 +66,16 @@
66 if(zPathInfo==0){
67 rc = 0;
68 }else if(0==strncmp("/json",zPathInfo,5)
69 && (zPathInfo[5]==0 || zPathInfo[5]=='/')){
70 rc = 1;
71 }else if(g.zCmdName!=0 && 0==strcmp("server",g.zCmdName)){
72 /* When running in server "directory" mode, zPathInfo is
 
73 ** prefixed with the repository's name, so in order to determine
74 ** whether or not we're really running in json mode we have to
75 ** try a bit harder. Problem reported here:
76 ** https://fossil-scm.org/forum/forumpost/e4953666d6
77 */
78 ReCompiled * pReg = 0;
79 const char * zErr = re_compile(&pReg, "^/[^/]+/json(/.*)?", 0);
80 assert(zErr==0 && "Regex compilation failed?");
@@ -687,11 +688,11 @@
687 ** connection is "local", any authToken provided by the user is
688 ** ignored and no new token is created: localauth mode trumps the
689 ** authToken.
690 */
691 cson_value * json_auth_token(){
692 assert(g.json.gc.a && "json_main_bootstrap() was not called!");
693 if( g.json.authToken==0 && g.noPswd==0
694 /* g.noPswd!=0 means the user was logged in via a local
695 connection using --localauth. */
696 ){
697 /* Try to get an authorization token from GET parameter, POSTed
@@ -740,43 +741,49 @@
740 cson_value * json_req_payload_get(char const *pKey){
741 return g.json.reqPayload.o
742 ? cson_object_get(g.json.reqPayload.o,pKey)
743 : NULL;
744 }
 
745
746 /*
747 ** Returns non-zero if the json_main_bootstrap() function has already
748 ** been called. In general, this function should be used sparingly,
749 ** e.g. from low-level support functions like fossil_warning() where
750 ** there is genuine uncertainty about whether (or not) the JSON setup
751 ** has already been called.
752 */
753 int json_is_main_boostrapped(){
754 return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
755 }
756
757 /*
758 ** Initializes some JSON bits which need to be initialized relatively
759 ** early on. It should only be called from cgi_init() or
760 ** json_cmd_top() (early on in those functions).
 
 
 
761 **
762 ** Initializes g.json.gc and g.json.param. This code does not (and
763 ** must not) rely on any of the fossil environment having been set
764 ** up. e.g. it must not use cgi_parameter() and friends because this
765 ** must be called before those data are initialized.
 
 
766 */
767 void json_main_bootstrap(){
768 cson_value * v;
769 assert( (NULL == g.json.gc.v) &&
770 "json_main_bootstrap() was called twice!" );
771
 
 
 
 
772 g.json.timerId = fossil_timer_start();
773
774 /* g.json.gc is our "garbage collector" - where we put JSON values
775 which need a long lifetime but don't have a logical parent to put
776 them in.
777 */
778 v = cson_value_new_array();
779 g.json.gc.v = v;
780 assert(0 != g.json.gc.v);
781 g.json.gc.a = cson_value_get_array(v);
782 assert(0 != g.json.gc.a);
@@ -783,12 +790,11 @@
783 cson_value_add_reference(v)
784 /* Needed to allow us to include this value in other JSON
785 containers without transferring ownership to those containers.
786 All other persistent g.json.XXX.v values get appended to
787 g.json.gc.a, and therefore already have a live reference
788 for this purpose.
789 */
790 ;
791
792 /*
793 g.json.param holds the JSONized counterpart of fossil's
794 cgi_parameter_xxx() family of data. We store them as JSON, as
@@ -828,11 +834,11 @@
828 void json_warn( int code, char const * fmt, ... ){
829 cson_object * obj = NULL;
830 assert( (code>FSL_JSON_W_START)
831 && (code<FSL_JSON_W_END)
832 && "Invalid warning code.");
833 assert(g.json.gc.a && "json_main_bootstrap() was not called!");
834 if(!g.json.warnings){
835 g.json.warnings = cson_new_array();
836 assert((NULL != g.json.warnings) && "Alloc error.");
837 json_gc_add("$WARNINGS",cson_array_value(g.json.warnings));
838 }
@@ -975,15 +981,15 @@
975 ** This must be called by the top-level JSON command dispatching code
976 ** before they do any work.
977 **
978 ** This must only be called once, or an assertion may be triggered.
979 */
980 void json_mode_bootstrap(){
981 static char once = 0 /* guard against multiple runs */;
982 char const * zPath = P("PATH_INFO");
983 assert(g.json.gc.a && "json_main_bootstrap() was not called!");
984 assert( (0==once) && "json_mode_bootstrap() called too many times!");
985 if( once ){
986 return;
987 }else{
988 once = 1;
989 }
@@ -1158,11 +1164,11 @@
1158 ** find_option() to get those.
1159 **
1160 */
1161 char const * json_command_arg(unsigned short ndx){
1162 cson_array * ar = g.json.cmd.a;
1163 assert((NULL!=ar) && "Internal error. Was json_mode_bootstrap() called?");
1164 assert((g.argc>1) && "Internal error - we never should have gotten this far.");
1165 if( g.json.cmd.offset < 0 ){
1166 /* first-time setup. */
1167 short i = 0;
1168 #define NEXT cson_string_cstr( \
@@ -2305,12 +2311,12 @@
2305 ** This function dispatches them, and is the HTTP equivalent of
2306 ** json_cmd_top().
2307 */
2308 void json_page_top(void){
2309 char const * zCommand;
2310 assert(g.json.gc.a && "json_main_bootstrap() was not called!");
2311 assert(g.json.cmd.a && "json_mode_bootstrap() was not called!");
2312 zCommand = json_command_arg(1);
2313 if(!zCommand || !*zCommand){
2314 json_dispatch_missing_args_err( JsonPageDefs,
2315 "No command (sub-path) specified."
2316 " Try one of: ");
@@ -2377,12 +2383,12 @@
2377 mode but (B) having them set gives us one less
2378 difference in the CLI/CGI/Server-mode JSON
2379 handling.
2380 */
2381 ;
2382 json_main_bootstrap();
2383 json_mode_bootstrap();
2384 if( 2 > cson_array_length_get(g.json.cmd.a) ){
2385 goto usage;
2386 }
2387 #if 0
2388 json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
2389
--- src/json.c
+++ src/json.c
@@ -55,11 +55,11 @@
55 };
56
57 /*
58 ** Given the current request path string, this function returns true
59 ** if it refers to a JSON API path. i.e. if (1) it starts with /json
60 ** or (2) g.zCmdName is "server" or "cgi" and the path starts with
61 ** /somereponame/json. Specifically, it returns 1 in the former case
62 ** and 2 for the latter.
63 */
64 int json_request_is_json_api(const char * zPathInfo){
65 int rc = 0;
@@ -66,15 +66,16 @@
66 if(zPathInfo==0){
67 rc = 0;
68 }else if(0==strncmp("/json",zPathInfo,5)
69 && (zPathInfo[5]==0 || zPathInfo[5]=='/')){
70 rc = 1;
71 }else if(g.zCmdName!=0 && (0==strcmp("server",g.zCmdName)
72 || 0==strcmp("cgi",g.zCmdName)) ){
73 /* When running in server/cgi "directory" mode, zPathInfo is
74 ** prefixed with the repository's name, so in order to determine
75 ** whether or not we're really running in json mode we have to try
76 ** a bit harder. Problem reported here:
77 ** https://fossil-scm.org/forum/forumpost/e4953666d6
78 */
79 ReCompiled * pReg = 0;
80 const char * zErr = re_compile(&pReg, "^/[^/]+/json(/.*)?", 0);
81 assert(zErr==0 && "Regex compilation failed?");
@@ -687,11 +688,11 @@
688 ** connection is "local", any authToken provided by the user is
689 ** ignored and no new token is created: localauth mode trumps the
690 ** authToken.
691 */
692 cson_value * json_auth_token(){
693 assert(g.json.gc.a && "json_bootstrap_early() was not called!");
694 if( g.json.authToken==0 && g.noPswd==0
695 /* g.noPswd!=0 means the user was logged in via a local
696 connection using --localauth. */
697 ){
698 /* Try to get an authorization token from GET parameter, POSTed
@@ -740,43 +741,49 @@
741 cson_value * json_req_payload_get(char const *pKey){
742 return g.json.reqPayload.o
743 ? cson_object_get(g.json.reqPayload.o,pKey)
744 : NULL;
745 }
746
747
748 /*
749 ** Returns non-zero if the json_bootstrap_early() function has already
750 ** been called. In general, this function should be used sparingly,
751 ** e.g. from low-level support functions like fossil_warning() where
752 ** there is genuine uncertainty about whether (or not) the JSON setup
753 ** has already been called.
754 */
755 int json_is_bootstrapped_early(){
756 return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
757 }
758
759 /*
760 ** Initializes some JSON bits which need to be initialized relatively
761 ** early on. It should be called by any routine which might need to
762 ** call into JSON relatively early on in the init process.
763 ** Specifically, early on in cgi_init() and json_cmd_top(), but also
764 ** from any error reporting routines which might be triggered (early
765 ** on in those functions).
766 **
767 ** Initializes g.json.gc and g.json.param. This code does not (and
768 ** must not) rely on any of the fossil environment having been set
769 ** up. e.g. it must not use cgi_parameter() and friends because this
770 ** must be called before those data are initialized.
771 **
772 ** If called multiple times, calls after the first are a no-op.
773 */
774 void json_bootstrap_early(){
775 cson_value * v;
 
 
776
777 if(g.json.gc.v!=NULL){
778 /* Avoid multiple bootstrappings. */
779 return;
780 }
781 g.json.timerId = fossil_timer_start();
 
782 /* g.json.gc is our "garbage collector" - where we put JSON values
783 which need a long lifetime but don't have a logical parent to put
784 them in. */
 
785 v = cson_value_new_array();
786 g.json.gc.v = v;
787 assert(0 != g.json.gc.v);
788 g.json.gc.a = cson_value_get_array(v);
789 assert(0 != g.json.gc.a);
@@ -783,12 +790,11 @@
790 cson_value_add_reference(v)
791 /* Needed to allow us to include this value in other JSON
792 containers without transferring ownership to those containers.
793 All other persistent g.json.XXX.v values get appended to
794 g.json.gc.a, and therefore already have a live reference
795 for this purpose. */
 
796 ;
797
798 /*
799 g.json.param holds the JSONized counterpart of fossil's
800 cgi_parameter_xxx() family of data. We store them as JSON, as
@@ -828,11 +834,11 @@
834 void json_warn( int code, char const * fmt, ... ){
835 cson_object * obj = NULL;
836 assert( (code>FSL_JSON_W_START)
837 && (code<FSL_JSON_W_END)
838 && "Invalid warning code.");
839 assert(g.json.gc.a && "json_bootstrap_early() was not called!");
840 if(!g.json.warnings){
841 g.json.warnings = cson_new_array();
842 assert((NULL != g.json.warnings) && "Alloc error.");
843 json_gc_add("$WARNINGS",cson_array_value(g.json.warnings));
844 }
@@ -975,15 +981,15 @@
981 ** This must be called by the top-level JSON command dispatching code
982 ** before they do any work.
983 **
984 ** This must only be called once, or an assertion may be triggered.
985 */
986 void json_bootstrap_late(){
987 static char once = 0 /* guard against multiple runs */;
988 char const * zPath = P("PATH_INFO");
989 assert(g.json.gc.a && "json_bootstrap_early() was not called!");
990 assert( (0==once) && "json_bootstrap_late() called too many times!");
991 if( once ){
992 return;
993 }else{
994 once = 1;
995 }
@@ -1158,11 +1164,11 @@
1164 ** find_option() to get those.
1165 **
1166 */
1167 char const * json_command_arg(unsigned short ndx){
1168 cson_array * ar = g.json.cmd.a;
1169 assert((NULL!=ar) && "Internal error. Was json_bootstrap_late() called?");
1170 assert((g.argc>1) && "Internal error - we never should have gotten this far.");
1171 if( g.json.cmd.offset < 0 ){
1172 /* first-time setup. */
1173 short i = 0;
1174 #define NEXT cson_string_cstr( \
@@ -2305,12 +2311,12 @@
2311 ** This function dispatches them, and is the HTTP equivalent of
2312 ** json_cmd_top().
2313 */
2314 void json_page_top(void){
2315 char const * zCommand;
2316 assert(g.json.gc.a && "json_bootstrap_early() was not called!");
2317 assert(g.json.cmd.a && "json_bootstrap_late() was not called!");
2318 zCommand = json_command_arg(1);
2319 if(!zCommand || !*zCommand){
2320 json_dispatch_missing_args_err( JsonPageDefs,
2321 "No command (sub-path) specified."
2322 " Try one of: ");
@@ -2377,12 +2383,12 @@
2383 mode but (B) having them set gives us one less
2384 difference in the CLI/CGI/Server-mode JSON
2385 handling.
2386 */
2387 ;
2388 json_bootstrap_early();
2389 json_bootstrap_late();
2390 if( 2 > cson_array_length_get(g.json.cmd.a) ){
2391 goto usage;
2392 }
2393 #if 0
2394 json_warn(FSL_JSON_W_ROW_TO_JSON_FAILED, "Just testing.");
2395
--- src/json_login.c
+++ src/json_login.c
@@ -183,11 +183,11 @@
183183
** Impl of /json/logout.
184184
**
185185
*/
186186
cson_value * json_page_logout(){
187187
cson_value const *token = g.json.authToken;
188
- /* Remember that json_mode_bootstrap() replaces the login cookie
188
+ /* Remember that json_bootstrap_late() replaces the login cookie
189189
with the JSON auth token if the request contains it. If the
190190
request is missing the auth token then this will fetch fossil's
191191
original cookie. Either way, it's what we want :).
192192
193193
We require the auth token to avoid someone maliciously
194194
--- src/json_login.c
+++ src/json_login.c
@@ -183,11 +183,11 @@
183 ** Impl of /json/logout.
184 **
185 */
186 cson_value * json_page_logout(){
187 cson_value const *token = g.json.authToken;
188 /* Remember that json_mode_bootstrap() replaces the login cookie
189 with the JSON auth token if the request contains it. If the
190 request is missing the auth token then this will fetch fossil's
191 original cookie. Either way, it's what we want :).
192
193 We require the auth token to avoid someone maliciously
194
--- src/json_login.c
+++ src/json_login.c
@@ -183,11 +183,11 @@
183 ** Impl of /json/logout.
184 **
185 */
186 cson_value * json_page_logout(){
187 cson_value const *token = g.json.authToken;
188 /* Remember that json_bootstrap_late() replaces the login cookie
189 with the JSON auth token if the request contains it. If the
190 request is missing the auth token then this will fetch fossil's
191 original cookie. Either way, it's what we want :).
192
193 We require the auth token to avoid someone maliciously
194
+8 -6
--- src/main.c
+++ src/main.c
@@ -1579,12 +1579,13 @@
15791579
** process JSON-mode POST data if we're actually in a /json
15801580
** page). This is normally set up before this routine is called, but
15811581
** it looks like the ssh_request_loop() approach to dispatching
15821582
** might bypass that.
15831583
*/
1584
- if( g.json.isJsonMode==0 && json_request_is_json_api(zPathInfo) ){
1584
+ if( g.json.isJsonMode==0 && json_request_is_json_api(zPathInfo)!=0 ){
15851585
g.json.isJsonMode = 1;
1586
+ json_bootstrap_early();
15861587
}
15871588
#endif
15881589
/* If the repository has not been opened already, then find the
15891590
** repository based on the first element of PATH_INFO and open it.
15901591
*/
@@ -1857,11 +1858,11 @@
18571858
** of grief with this handling. The JSON API never relies on the
18581859
** handling below, and by disabling it in JSON mode I can remove
18591860
** lots of special-case handling in several JSON handlers.
18601861
*/
18611862
#ifdef FOSSIL_ENABLE_JSON
1862
- if(!g.json.isJsonMode){
1863
+ if(g.json.isJsonMode==0){
18631864
#endif
18641865
dehttpize(g.zExtra);
18651866
cgi_set_parameter_nocopy("name", g.zExtra, 1);
18661867
#ifdef FOSSIL_ENABLE_JSON
18671868
}
@@ -1873,11 +1874,11 @@
18731874
*/
18741875
if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
18751876
&& dispatch_alias(g.zPath-1, &pCmd)
18761877
){
18771878
#ifdef FOSSIL_ENABLE_JSON
1878
- if(g.json.isJsonMode){
1879
+ if(g.json.isJsonMode!=0){
18791880
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
18801881
}else
18811882
#endif
18821883
{
18831884
#ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -1901,11 +1902,11 @@
19011902
}
19021903
#endif
19031904
}
19041905
}else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
19051906
#ifdef FOSSIL_ENABLE_JSON
1906
- if(g.json.isJsonMode){
1907
+ if(g.json.isJsonMode!=0){
19071908
json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
19081909
}else
19091910
#endif
19101911
{
19111912
@ <h1>Server Configuration Error</h1>
@@ -1913,12 +1914,13 @@
19131914
@ the administrator to run <b>fossil rebuild</b>.</p>
19141915
}
19151916
}else{
19161917
#ifdef FOSSIL_ENABLE_JSON
19171918
static int jsonOnce = 0;
1918
- if( !jsonOnce && g.json.isJsonMode ){
1919
- json_mode_bootstrap();
1919
+ if( jsonOnce==0 && g.json.isJsonMode!=0 ){
1920
+ assert(json_is_bootstrapped_early());
1921
+ json_bootstrap_late();
19201922
jsonOnce = 1;
19211923
}
19221924
#endif
19231925
if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
19241926
cgi_decode_post_parameters();
19251927
--- src/main.c
+++ src/main.c
@@ -1579,12 +1579,13 @@
1579 ** process JSON-mode POST data if we're actually in a /json
1580 ** page). This is normally set up before this routine is called, but
1581 ** it looks like the ssh_request_loop() approach to dispatching
1582 ** might bypass that.
1583 */
1584 if( g.json.isJsonMode==0 && json_request_is_json_api(zPathInfo) ){
1585 g.json.isJsonMode = 1;
 
1586 }
1587 #endif
1588 /* If the repository has not been opened already, then find the
1589 ** repository based on the first element of PATH_INFO and open it.
1590 */
@@ -1857,11 +1858,11 @@
1857 ** of grief with this handling. The JSON API never relies on the
1858 ** handling below, and by disabling it in JSON mode I can remove
1859 ** lots of special-case handling in several JSON handlers.
1860 */
1861 #ifdef FOSSIL_ENABLE_JSON
1862 if(!g.json.isJsonMode){
1863 #endif
1864 dehttpize(g.zExtra);
1865 cgi_set_parameter_nocopy("name", g.zExtra, 1);
1866 #ifdef FOSSIL_ENABLE_JSON
1867 }
@@ -1873,11 +1874,11 @@
1873 */
1874 if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
1875 && dispatch_alias(g.zPath-1, &pCmd)
1876 ){
1877 #ifdef FOSSIL_ENABLE_JSON
1878 if(g.json.isJsonMode){
1879 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
1880 }else
1881 #endif
1882 {
1883 #ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -1901,11 +1902,11 @@
1901 }
1902 #endif
1903 }
1904 }else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
1905 #ifdef FOSSIL_ENABLE_JSON
1906 if(g.json.isJsonMode){
1907 json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
1908 }else
1909 #endif
1910 {
1911 @ <h1>Server Configuration Error</h1>
@@ -1913,12 +1914,13 @@
1913 @ the administrator to run <b>fossil rebuild</b>.</p>
1914 }
1915 }else{
1916 #ifdef FOSSIL_ENABLE_JSON
1917 static int jsonOnce = 0;
1918 if( !jsonOnce && g.json.isJsonMode ){
1919 json_mode_bootstrap();
 
1920 jsonOnce = 1;
1921 }
1922 #endif
1923 if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
1924 cgi_decode_post_parameters();
1925
--- src/main.c
+++ src/main.c
@@ -1579,12 +1579,13 @@
1579 ** process JSON-mode POST data if we're actually in a /json
1580 ** page). This is normally set up before this routine is called, but
1581 ** it looks like the ssh_request_loop() approach to dispatching
1582 ** might bypass that.
1583 */
1584 if( g.json.isJsonMode==0 && json_request_is_json_api(zPathInfo)!=0 ){
1585 g.json.isJsonMode = 1;
1586 json_bootstrap_early();
1587 }
1588 #endif
1589 /* If the repository has not been opened already, then find the
1590 ** repository based on the first element of PATH_INFO and open it.
1591 */
@@ -1857,11 +1858,11 @@
1858 ** of grief with this handling. The JSON API never relies on the
1859 ** handling below, and by disabling it in JSON mode I can remove
1860 ** lots of special-case handling in several JSON handlers.
1861 */
1862 #ifdef FOSSIL_ENABLE_JSON
1863 if(g.json.isJsonMode==0){
1864 #endif
1865 dehttpize(g.zExtra);
1866 cgi_set_parameter_nocopy("name", g.zExtra, 1);
1867 #ifdef FOSSIL_ENABLE_JSON
1868 }
@@ -1873,11 +1874,11 @@
1874 */
1875 if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
1876 && dispatch_alias(g.zPath-1, &pCmd)
1877 ){
1878 #ifdef FOSSIL_ENABLE_JSON
1879 if(g.json.isJsonMode!=0){
1880 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
1881 }else
1882 #endif
1883 {
1884 #ifdef FOSSIL_ENABLE_TH1_HOOKS
@@ -1901,11 +1902,11 @@
1902 }
1903 #endif
1904 }
1905 }else if( pCmd->xFunc!=page_xfer && db_schema_is_outofdate() ){
1906 #ifdef FOSSIL_ENABLE_JSON
1907 if(g.json.isJsonMode!=0){
1908 json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
1909 }else
1910 #endif
1911 {
1912 @ <h1>Server Configuration Error</h1>
@@ -1913,12 +1914,13 @@
1914 @ the administrator to run <b>fossil rebuild</b>.</p>
1915 }
1916 }else{
1917 #ifdef FOSSIL_ENABLE_JSON
1918 static int jsonOnce = 0;
1919 if( jsonOnce==0 && g.json.isJsonMode!=0 ){
1920 assert(json_is_bootstrapped_early());
1921 json_bootstrap_late();
1922 jsonOnce = 1;
1923 }
1924 #endif
1925 if( (pCmd->eCmdFlags & CMDFLAG_RAWCONTENT)==0 ){
1926 cgi_decode_post_parameters();
1927
+4 -4
--- src/printf.c
+++ src/printf.c
@@ -1075,17 +1075,17 @@
10751075
/*
10761076
** Write error message output
10771077
*/
10781078
static int fossil_print_error(int rc, const char *z){
10791079
#ifdef FOSSIL_ENABLE_JSON
1080
- if( g.json.isJsonMode ){
1080
+ if( g.json.isJsonMode!=0 ){
10811081
/*
10821082
** Avoid calling into the JSON support subsystem if it
10831083
** has not yet been initialized, e.g. early SQLite log
10841084
** messages, etc.
10851085
*/
1086
- if( !json_is_main_boostrapped() ) json_main_bootstrap();
1086
+ assert(json_is_bootstrapped_early());
10871087
json_err( 0, z, 1 );
10881088
if( g.isHTTP && !g.json.preserveRc ){
10891089
rc = 0 /* avoid HTTP 500 */;
10901090
}
10911091
if( g.cgiOutput==1 ){
@@ -1201,17 +1201,17 @@
12011201
va_start(ap, zFormat);
12021202
z = vmprintf(zFormat, ap);
12031203
va_end(ap);
12041204
fossil_errorlog("warning: %s", z);
12051205
#ifdef FOSSIL_ENABLE_JSON
1206
- if(g.json.isJsonMode){
1206
+ if( g.json.isJsonMode!=0 ){
12071207
/*
12081208
** Avoid calling into the JSON support subsystem if it
12091209
** has not yet been initialized, e.g. early SQLite log
12101210
** messages, etc.
12111211
*/
1212
- if( !json_is_main_boostrapped() ) json_main_bootstrap();
1212
+ assert(json_is_bootstrapped_early());
12131213
json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
12141214
}else
12151215
#endif
12161216
{
12171217
if( g.cgiOutput==1 ){
12181218
--- src/printf.c
+++ src/printf.c
@@ -1075,17 +1075,17 @@
1075 /*
1076 ** Write error message output
1077 */
1078 static int fossil_print_error(int rc, const char *z){
1079 #ifdef FOSSIL_ENABLE_JSON
1080 if( g.json.isJsonMode ){
1081 /*
1082 ** Avoid calling into the JSON support subsystem if it
1083 ** has not yet been initialized, e.g. early SQLite log
1084 ** messages, etc.
1085 */
1086 if( !json_is_main_boostrapped() ) json_main_bootstrap();
1087 json_err( 0, z, 1 );
1088 if( g.isHTTP && !g.json.preserveRc ){
1089 rc = 0 /* avoid HTTP 500 */;
1090 }
1091 if( g.cgiOutput==1 ){
@@ -1201,17 +1201,17 @@
1201 va_start(ap, zFormat);
1202 z = vmprintf(zFormat, ap);
1203 va_end(ap);
1204 fossil_errorlog("warning: %s", z);
1205 #ifdef FOSSIL_ENABLE_JSON
1206 if(g.json.isJsonMode){
1207 /*
1208 ** Avoid calling into the JSON support subsystem if it
1209 ** has not yet been initialized, e.g. early SQLite log
1210 ** messages, etc.
1211 */
1212 if( !json_is_main_boostrapped() ) json_main_bootstrap();
1213 json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
1214 }else
1215 #endif
1216 {
1217 if( g.cgiOutput==1 ){
1218
--- src/printf.c
+++ src/printf.c
@@ -1075,17 +1075,17 @@
1075 /*
1076 ** Write error message output
1077 */
1078 static int fossil_print_error(int rc, const char *z){
1079 #ifdef FOSSIL_ENABLE_JSON
1080 if( g.json.isJsonMode!=0 ){
1081 /*
1082 ** Avoid calling into the JSON support subsystem if it
1083 ** has not yet been initialized, e.g. early SQLite log
1084 ** messages, etc.
1085 */
1086 assert(json_is_bootstrapped_early());
1087 json_err( 0, z, 1 );
1088 if( g.isHTTP && !g.json.preserveRc ){
1089 rc = 0 /* avoid HTTP 500 */;
1090 }
1091 if( g.cgiOutput==1 ){
@@ -1201,17 +1201,17 @@
1201 va_start(ap, zFormat);
1202 z = vmprintf(zFormat, ap);
1203 va_end(ap);
1204 fossil_errorlog("warning: %s", z);
1205 #ifdef FOSSIL_ENABLE_JSON
1206 if( g.json.isJsonMode!=0 ){
1207 /*
1208 ** Avoid calling into the JSON support subsystem if it
1209 ** has not yet been initialized, e.g. early SQLite log
1210 ** messages, etc.
1211 */
1212 assert(json_is_bootstrapped_early());
1213 json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
1214 }else
1215 #endif
1216 {
1217 if( g.cgiOutput==1 ){
1218

Keyboard Shortcuts

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