Fossil SCM

fixed an inconsistency in the CLI/CGI args/path handling. Non-CGI server mode is still broken b/c we do not yet have the PATH_INFO (or equivalent) data.

stephan 2011-09-16 16:38 UTC json
Commit 73591cc746f12189145481aa653a3a20b7d2bb7d
2 files changed +58 -12 +6
+58 -12
--- src/json.c
+++ src/json.c
@@ -256,29 +256,67 @@
256256
** is malformed.
257257
*/
258258
static void json_mode_bootstrap(){
259259
g.json.isJsonMode = 1;
260260
g.json.resultCode = 0;
261
+ g.json.cmdOffset = -1;
261262
#if defined(NDEBUG)
262263
/* avoids debug messages on stderr in JSON mode */
263264
sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0);
264265
#endif
266
+ /* g.json.reqPayload exists only to simplify some of our access to
267
+ the request payload. We only use this in the context of Object
268
+ payloads, not Arrays, strings, etc. */
265269
g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" );
266270
if( g.json.reqPayload.v ){
267
- g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v );
268
- if( ! g.json.reqPayload.o ){/* POST data is an array, which we can't use. */
269
- assert( cson_value_is_array( g.json.reqPayload.v ) );
270
- g.json.reqPayload.v = NULL;
271
- }
271
+ g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v )
272
+ /* g.json.reqPayload.o may legally be NULL, which means only that
273
+ g.json.reqPayload.v is-not-a Object.
274
+ */;
272275
}
273276
json_auth_token()/* will copy our auth token, if any, to fossil's core. */;
274277
if( g.isCGI ){
275278
login_check_credentials();
276279
}
277280
else{
278281
db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
279282
}
283
+
284
+}
285
+
286
+/*
287
+** Returns the ndx'th item in the PATH_INFO path, where index 0 is
288
+** the position of the "json" part of the path. Returns NULL if ndx
289
+** is out of bounds or there is no "json" path element.
290
+*/
291
+static char const * json_path_part(unsigned char ndx){
292
+ if( g.json.cmdOffset < 0 ){
293
+ /* first-time setup. */
294
+ short i = g.isCGI ? 0 : 1;
295
+#define NEXT (g.isCGI \
296
+ ? cson_cgi_path_part_cstr( &g.json.cgiCx, i ) \
297
+ : ((g.argc > i) ? g.argv[i] : NULL))
298
+ char const * tok = NEXT;
299
+ while( tok ){
300
+ if( 0==strncmp("json",tok,4) ){
301
+ g.json.cmdOffset = i;
302
+ break;
303
+ }
304
+ ++i;
305
+ tok = NEXT;
306
+#undef NEXT
307
+ }
308
+ }
309
+ if( g.json.cmdOffset < 0 ){
310
+ return NULL;
311
+ }else{
312
+ ndx = g.json.cmdOffset + ndx;
313
+ return g.isCGI
314
+ ? cson_cgi_path_part_cstr( &g.json.cgiCx, g.json.cmdOffset + ndx )
315
+ : ((ndx < g.argc) ? g.argv[ndx] : NULL)
316
+ ;
317
+ }
280318
}
281319
282320
/*
283321
** If g.json.reqPayload.o is NULL then NULL is returned, else the
284322
** given property is searched for in the request payload. If found it
@@ -439,10 +477,19 @@
439477
tmp = payload;
440478
SET("payload");
441479
}
442480
}
443481
#undef SET
482
+ if(0){/*only for my own debuggering*/
483
+ tmp = cson_cgi_env_get_val(&g.json.cgiCx,'e', 0);
484
+ if(tmp){
485
+ cson_object_set( o, "$ENV", tmp );
486
+ }
487
+ tmp = cson_value_new_integer( g.json.cmdOffset );
488
+ cson_object_set( o, "cmdOffset", tmp );
489
+ }
490
+
444491
goto ok;
445492
cleanup:
446493
cson_value_free(v);
447494
v = NULL;
448495
ok:
@@ -747,11 +794,11 @@
747794
/* Last entry MUST have a NULL name. */
748795
{NULL,NULL}
749796
};
750797
751798
/*
752
-** WEBPAGE: /json
799
+** WEBPAGE: json
753800
**
754801
** Pages under /json/... must be entered into JsonPageDefs.
755802
*/
756803
void json_page_top(void){
757804
int rc = FSL_JSON_E_UNKNOWN_COMMAND;
@@ -758,24 +805,23 @@
758805
Blob buf = empty_blob;
759806
char const * cmd;
760807
cson_value * payload = NULL;
761808
cson_value * root = NULL;
762809
JsonPageDef const * pageDef = NULL;
810
+ cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
763811
json_mode_bootstrap();
764
- cmd = cson_cgi_path_part_cstr(&g.json.cgiCx,1);
812
+ cmd = json_path_part(1);
765813
pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
766
- cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
767814
if( ! pageDef ){
768
- json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 0 );
815
+ json_err( FSL_JSON_E_UNKNOWN_COMMAND, cmd, 0 );
769816
return;
770817
}else if( pageDef->runMode < 0 /*CLI only*/) {
771818
rc = FSL_JSON_E_WRONG_MODE;
772819
}else{
773820
rc = 0;
774821
payload = (*pageDef->func)();
775822
}
776
- /* FIXME: we need a way of channeling resultCode values back here. */
777823
if( g.json.resultCode ){
778824
json_err(g.json.resultCode, NULL, 0);
779825
}else{
780826
blob_zero(&buf);
781827
root = json_response_skeleton(rc, payload, NULL);
@@ -813,19 +859,19 @@
813859
json_mode_bootstrap();
814860
db_find_and_open_repository(0, 0);
815861
if( g.argc<3 ){
816862
goto usage;
817863
}
818
- cmd = g.argv[2];
864
+ cmd = json_path_part(1);
819865
n = cmd ? strlen(cmd) : 0;
820866
if( n==0 ){
821867
goto usage;
822868
}
823869
cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
824870
pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
825871
if( ! pageDef ){
826
- json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 0 );
872
+ json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 1 );
827873
return;
828874
}else if( pageDef->runMode > 0 /*HTTP only*/) {
829875
rc = FSL_JSON_E_WRONG_MODE;
830876
}else{
831877
rc = 0;
832878
--- src/json.c
+++ src/json.c
@@ -256,29 +256,67 @@
256 ** is malformed.
257 */
258 static void json_mode_bootstrap(){
259 g.json.isJsonMode = 1;
260 g.json.resultCode = 0;
 
261 #if defined(NDEBUG)
262 /* avoids debug messages on stderr in JSON mode */
263 sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0);
264 #endif
 
 
 
265 g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" );
266 if( g.json.reqPayload.v ){
267 g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v );
268 if( ! g.json.reqPayload.o ){/* POST data is an array, which we can't use. */
269 assert( cson_value_is_array( g.json.reqPayload.v ) );
270 g.json.reqPayload.v = NULL;
271 }
272 }
273 json_auth_token()/* will copy our auth token, if any, to fossil's core. */;
274 if( g.isCGI ){
275 login_check_credentials();
276 }
277 else{
278 db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
279 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280 }
281
282 /*
283 ** If g.json.reqPayload.o is NULL then NULL is returned, else the
284 ** given property is searched for in the request payload. If found it
@@ -439,10 +477,19 @@
439 tmp = payload;
440 SET("payload");
441 }
442 }
443 #undef SET
 
 
 
 
 
 
 
 
 
444 goto ok;
445 cleanup:
446 cson_value_free(v);
447 v = NULL;
448 ok:
@@ -747,11 +794,11 @@
747 /* Last entry MUST have a NULL name. */
748 {NULL,NULL}
749 };
750
751 /*
752 ** WEBPAGE: /json
753 **
754 ** Pages under /json/... must be entered into JsonPageDefs.
755 */
756 void json_page_top(void){
757 int rc = FSL_JSON_E_UNKNOWN_COMMAND;
@@ -758,24 +805,23 @@
758 Blob buf = empty_blob;
759 char const * cmd;
760 cson_value * payload = NULL;
761 cson_value * root = NULL;
762 JsonPageDef const * pageDef = NULL;
 
763 json_mode_bootstrap();
764 cmd = cson_cgi_path_part_cstr(&g.json.cgiCx,1);
765 pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
766 cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
767 if( ! pageDef ){
768 json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 0 );
769 return;
770 }else if( pageDef->runMode < 0 /*CLI only*/) {
771 rc = FSL_JSON_E_WRONG_MODE;
772 }else{
773 rc = 0;
774 payload = (*pageDef->func)();
775 }
776 /* FIXME: we need a way of channeling resultCode values back here. */
777 if( g.json.resultCode ){
778 json_err(g.json.resultCode, NULL, 0);
779 }else{
780 blob_zero(&buf);
781 root = json_response_skeleton(rc, payload, NULL);
@@ -813,19 +859,19 @@
813 json_mode_bootstrap();
814 db_find_and_open_repository(0, 0);
815 if( g.argc<3 ){
816 goto usage;
817 }
818 cmd = g.argv[2];
819 n = cmd ? strlen(cmd) : 0;
820 if( n==0 ){
821 goto usage;
822 }
823 cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
824 pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
825 if( ! pageDef ){
826 json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 0 );
827 return;
828 }else if( pageDef->runMode > 0 /*HTTP only*/) {
829 rc = FSL_JSON_E_WRONG_MODE;
830 }else{
831 rc = 0;
832
--- src/json.c
+++ src/json.c
@@ -256,29 +256,67 @@
256 ** is malformed.
257 */
258 static void json_mode_bootstrap(){
259 g.json.isJsonMode = 1;
260 g.json.resultCode = 0;
261 g.json.cmdOffset = -1;
262 #if defined(NDEBUG)
263 /* avoids debug messages on stderr in JSON mode */
264 sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0);
265 #endif
266 /* g.json.reqPayload exists only to simplify some of our access to
267 the request payload. We only use this in the context of Object
268 payloads, not Arrays, strings, etc. */
269 g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" );
270 if( g.json.reqPayload.v ){
271 g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v )
272 /* g.json.reqPayload.o may legally be NULL, which means only that
273 g.json.reqPayload.v is-not-a Object.
274 */;
 
275 }
276 json_auth_token()/* will copy our auth token, if any, to fossil's core. */;
277 if( g.isCGI ){
278 login_check_credentials();
279 }
280 else{
281 db_find_and_open_repository(OPEN_ANY_SCHEMA,0);
282 }
283
284 }
285
286 /*
287 ** Returns the ndx'th item in the PATH_INFO path, where index 0 is
288 ** the position of the "json" part of the path. Returns NULL if ndx
289 ** is out of bounds or there is no "json" path element.
290 */
291 static char const * json_path_part(unsigned char ndx){
292 if( g.json.cmdOffset < 0 ){
293 /* first-time setup. */
294 short i = g.isCGI ? 0 : 1;
295 #define NEXT (g.isCGI \
296 ? cson_cgi_path_part_cstr( &g.json.cgiCx, i ) \
297 : ((g.argc > i) ? g.argv[i] : NULL))
298 char const * tok = NEXT;
299 while( tok ){
300 if( 0==strncmp("json",tok,4) ){
301 g.json.cmdOffset = i;
302 break;
303 }
304 ++i;
305 tok = NEXT;
306 #undef NEXT
307 }
308 }
309 if( g.json.cmdOffset < 0 ){
310 return NULL;
311 }else{
312 ndx = g.json.cmdOffset + ndx;
313 return g.isCGI
314 ? cson_cgi_path_part_cstr( &g.json.cgiCx, g.json.cmdOffset + ndx )
315 : ((ndx < g.argc) ? g.argv[ndx] : NULL)
316 ;
317 }
318 }
319
320 /*
321 ** If g.json.reqPayload.o is NULL then NULL is returned, else the
322 ** given property is searched for in the request payload. If found it
@@ -439,10 +477,19 @@
477 tmp = payload;
478 SET("payload");
479 }
480 }
481 #undef SET
482 if(0){/*only for my own debuggering*/
483 tmp = cson_cgi_env_get_val(&g.json.cgiCx,'e', 0);
484 if(tmp){
485 cson_object_set( o, "$ENV", tmp );
486 }
487 tmp = cson_value_new_integer( g.json.cmdOffset );
488 cson_object_set( o, "cmdOffset", tmp );
489 }
490
491 goto ok;
492 cleanup:
493 cson_value_free(v);
494 v = NULL;
495 ok:
@@ -747,11 +794,11 @@
794 /* Last entry MUST have a NULL name. */
795 {NULL,NULL}
796 };
797
798 /*
799 ** WEBPAGE: json
800 **
801 ** Pages under /json/... must be entered into JsonPageDefs.
802 */
803 void json_page_top(void){
804 int rc = FSL_JSON_E_UNKNOWN_COMMAND;
@@ -758,24 +805,23 @@
805 Blob buf = empty_blob;
806 char const * cmd;
807 cson_value * payload = NULL;
808 cson_value * root = NULL;
809 JsonPageDef const * pageDef = NULL;
810 cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
811 json_mode_bootstrap();
812 cmd = json_path_part(1);
813 pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
 
814 if( ! pageDef ){
815 json_err( FSL_JSON_E_UNKNOWN_COMMAND, cmd, 0 );
816 return;
817 }else if( pageDef->runMode < 0 /*CLI only*/) {
818 rc = FSL_JSON_E_WRONG_MODE;
819 }else{
820 rc = 0;
821 payload = (*pageDef->func)();
822 }
 
823 if( g.json.resultCode ){
824 json_err(g.json.resultCode, NULL, 0);
825 }else{
826 blob_zero(&buf);
827 root = json_response_skeleton(rc, payload, NULL);
@@ -813,19 +859,19 @@
859 json_mode_bootstrap();
860 db_find_and_open_repository(0, 0);
861 if( g.argc<3 ){
862 goto usage;
863 }
864 cmd = json_path_part(1);
865 n = cmd ? strlen(cmd) : 0;
866 if( n==0 ){
867 goto usage;
868 }
869 cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
870 pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
871 if( ! pageDef ){
872 json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 1 );
873 return;
874 }else if( pageDef->runMode > 0 /*HTTP only*/) {
875 rc = FSL_JSON_E_WRONG_MODE;
876 }else{
877 rc = 0;
878
+6
--- src/main.c
+++ src/main.c
@@ -173,10 +173,16 @@
173173
struct FossilJsonBits {
174174
int isJsonMode; /* True if running in JSON mode, else false. This changes
175175
how errors are reported. In JSON mode we try to always
176176
output JSON-form error responses.
177177
*/
178
+ int cmdOffset; /* Tells us which PATH_INFO/CLI args
179
+ part holds the "json" command, so
180
+ that we can account for sub-repos
181
+ and path prefixes. This is handled
182
+ differently for CLI and CGI modes.
183
+ */
178184
int resultCode; /* used for passing back specific codes from /json callbacks. */
179185
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
180186
cson_cgi_cx cgiCx; /* cson_cgi context */
181187
cson_output_opt outOpt; /* formatting options for JSON mode. */
182188
cson_value * authToken; /* authentication token */
183189
--- src/main.c
+++ src/main.c
@@ -173,10 +173,16 @@
173 struct FossilJsonBits {
174 int isJsonMode; /* True if running in JSON mode, else false. This changes
175 how errors are reported. In JSON mode we try to always
176 output JSON-form error responses.
177 */
 
 
 
 
 
 
178 int resultCode; /* used for passing back specific codes from /json callbacks. */
179 int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
180 cson_cgi_cx cgiCx; /* cson_cgi context */
181 cson_output_opt outOpt; /* formatting options for JSON mode. */
182 cson_value * authToken; /* authentication token */
183
--- src/main.c
+++ src/main.c
@@ -173,10 +173,16 @@
173 struct FossilJsonBits {
174 int isJsonMode; /* True if running in JSON mode, else false. This changes
175 how errors are reported. In JSON mode we try to always
176 output JSON-form error responses.
177 */
178 int cmdOffset; /* Tells us which PATH_INFO/CLI args
179 part holds the "json" command, so
180 that we can account for sub-repos
181 and path prefixes. This is handled
182 differently for CLI and CGI modes.
183 */
184 int resultCode; /* used for passing back specific codes from /json callbacks. */
185 int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
186 cson_cgi_cx cgiCx; /* cson_cgi context */
187 cson_output_opt outOpt; /* formatting options for JSON mode. */
188 cson_value * authToken; /* authentication token */
189

Keyboard Shortcuts

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