Fossil SCM
Consolidated server/cgi/cli path/arg handling (will break when add --options to CLI mode).
Commit
c5fbcced800163eac5449b306b6a1bf9f5ce249b
Parent
73591cc746f1218…
2 files changed
-1
+55
-4
-1
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -998,11 +998,10 @@ | ||
| 998 | 998 | char *z, *zToken; |
| 999 | 999 | int i; |
| 1000 | 1000 | struct sockaddr_in remoteName; |
| 1001 | 1001 | socklen_t size = sizeof(struct sockaddr_in); |
| 1002 | 1002 | char zLine[2000]; /* A single line of input. */ |
| 1003 | - | |
| 1004 | 1003 | g.fullHttpReply = 1; |
| 1005 | 1004 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1006 | 1005 | malformed_request(); |
| 1007 | 1006 | } |
| 1008 | 1007 | zToken = extract_token(zLine, &z); |
| 1009 | 1008 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -998,11 +998,10 @@ | |
| 998 | char *z, *zToken; |
| 999 | int i; |
| 1000 | struct sockaddr_in remoteName; |
| 1001 | socklen_t size = sizeof(struct sockaddr_in); |
| 1002 | char zLine[2000]; /* A single line of input. */ |
| 1003 | |
| 1004 | g.fullHttpReply = 1; |
| 1005 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1006 | malformed_request(); |
| 1007 | } |
| 1008 | zToken = extract_token(zLine, &z); |
| 1009 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -998,11 +998,10 @@ | |
| 998 | char *z, *zToken; |
| 999 | int i; |
| 1000 | struct sockaddr_in remoteName; |
| 1001 | socklen_t size = sizeof(struct sockaddr_in); |
| 1002 | char zLine[2000]; /* A single line of input. */ |
| 1003 | g.fullHttpReply = 1; |
| 1004 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1005 | malformed_request(); |
| 1006 | } |
| 1007 | zToken = extract_token(zLine, &z); |
| 1008 |
+55
-4
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -254,17 +254,55 @@ | ||
| 254 | 254 | ** but does not perform any authentication here. It _might_ |
| 255 | 255 | ** (haven't tested this) die with an error if an auth cookie |
| 256 | 256 | ** is malformed. |
| 257 | 257 | */ |
| 258 | 258 | static void json_mode_bootstrap(){ |
| 259 | + char const * zPath = P("PATH_INFO"); | |
| 259 | 260 | g.json.isJsonMode = 1; |
| 260 | 261 | g.json.resultCode = 0; |
| 261 | 262 | g.json.cmdOffset = -1; |
| 263 | + if( !g.isCGI && g.fullHttpReply ){ | |
| 264 | + g.isCGI = 1; | |
| 265 | + } | |
| 266 | + /*json_err( 1000, zPath, 1 ); exit(0);*/ | |
| 267 | + if( !zPath || !*zPath ){ | |
| 268 | + zPath = cson_string_cstr(cson_value_get_string(cson_cgi_getenv(&g.json.cgiCx,"e","PATH_INFO"))); | |
| 269 | + } | |
| 262 | 270 | #if defined(NDEBUG) |
| 263 | 271 | /* avoids debug messages on stderr in JSON mode */ |
| 264 | 272 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 265 | 273 | #endif |
| 274 | + if( zPath ){ | |
| 275 | + /* Translate fossil's PATH_INFO into cson_cgi for later | |
| 276 | + convenience, to help consolidate how we handle CGI/server | |
| 277 | + modes. | |
| 278 | + */ | |
| 279 | + char const * p = zPath; | |
| 280 | + char const * head = p; | |
| 281 | + unsigned int len = 0; | |
| 282 | + cson_value * piece = NULL; | |
| 283 | + cson_value * arV = cson_value_new_array(); | |
| 284 | + cson_array * ar = cson_value_get_array(arV); | |
| 285 | +#if 0 | |
| 286 | + cson_cgi_setenv( &g.json.cgiCx, "FOSSIL_PATH_INFO", cson_value_new_string(zPath,strlen(zPath)) ); | |
| 287 | +#endif | |
| 288 | + cson_cgi_setenv( &g.json.cgiCx, "COMMAND_PATH", arV ); | |
| 289 | + for( ;*p!='?'; ++p){ | |
| 290 | + if( !*p || ('/' == *p) ){ | |
| 291 | + if( len ) { | |
| 292 | + assert( head != p ); | |
| 293 | + piece = cson_value_new_string(head, len); | |
| 294 | + cson_array_append( ar, piece ); | |
| 295 | + len = 0; | |
| 296 | + } | |
| 297 | + if( !*p ) break; | |
| 298 | + head = p+1; | |
| 299 | + continue; | |
| 300 | + } | |
| 301 | + ++len; | |
| 302 | + } | |
| 303 | + } | |
| 266 | 304 | /* g.json.reqPayload exists only to simplify some of our access to |
| 267 | 305 | the request payload. We only use this in the context of Object |
| 268 | 306 | payloads, not Arrays, strings, etc. */ |
| 269 | 307 | g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" ); |
| 270 | 308 | if( g.json.reqPayload.v ){ |
| @@ -287,15 +325,25 @@ | ||
| 287 | 325 | ** Returns the ndx'th item in the PATH_INFO path, where index 0 is |
| 288 | 326 | ** the position of the "json" part of the path. Returns NULL if ndx |
| 289 | 327 | ** is out of bounds or there is no "json" path element. |
| 290 | 328 | */ |
| 291 | 329 | static char const * json_path_part(unsigned char ndx){ |
| 330 | + cson_array * ar = g.isCGI | |
| 331 | + ? cson_value_get_array(cson_cgi_getenv(&g.json.cgiCx,"a","COMMAND_PATH")) | |
| 332 | + : NULL; | |
| 333 | + if( g.isCGI ){ | |
| 334 | + assert((NULL!=ar) && "Internal error."); | |
| 335 | + } | |
| 292 | 336 | if( g.json.cmdOffset < 0 ){ |
| 293 | 337 | /* first-time setup. */ |
| 294 | 338 | short i = g.isCGI ? 0 : 1; |
| 339 | +#define PARTAT cson_string_cstr( \ | |
| 340 | + cson_value_get_string( \ | |
| 341 | + cson_array_get(ar,i) \ | |
| 342 | + )) | |
| 295 | 343 | #define NEXT (g.isCGI \ |
| 296 | - ? cson_cgi_path_part_cstr( &g.json.cgiCx, i ) \ | |
| 344 | + ? PARTAT \ | |
| 297 | 345 | : ((g.argc > i) ? g.argv[i] : NULL)) |
| 298 | 346 | char const * tok = NEXT; |
| 299 | 347 | while( tok ){ |
| 300 | 348 | if( 0==strncmp("json",tok,4) ){ |
| 301 | 349 | g.json.cmdOffset = i; |
| @@ -302,18 +350,19 @@ | ||
| 302 | 350 | break; |
| 303 | 351 | } |
| 304 | 352 | ++i; |
| 305 | 353 | tok = NEXT; |
| 306 | 354 | #undef NEXT |
| 355 | +#undef PARTAT | |
| 307 | 356 | } |
| 308 | 357 | } |
| 309 | 358 | if( g.json.cmdOffset < 0 ){ |
| 310 | 359 | return NULL; |
| 311 | 360 | }else{ |
| 312 | 361 | ndx = g.json.cmdOffset + ndx; |
| 313 | 362 | return g.isCGI |
| 314 | - ? cson_cgi_path_part_cstr( &g.json.cgiCx, g.json.cmdOffset + ndx ) | |
| 363 | + ? cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmdOffset + ndx ))) | |
| 315 | 364 | : ((ndx < g.argc) ? g.argv[ndx] : NULL) |
| 316 | 365 | ; |
| 317 | 366 | } |
| 318 | 367 | } |
| 319 | 368 | |
| @@ -478,16 +527,17 @@ | ||
| 478 | 527 | SET("payload"); |
| 479 | 528 | } |
| 480 | 529 | } |
| 481 | 530 | #undef SET |
| 482 | 531 | if(0){/*only for my own debuggering*/ |
| 483 | - tmp = cson_cgi_env_get_val(&g.json.cgiCx,'e', 0); | |
| 532 | + tmp = cson_cgi_env_get_val(&g.json.cgiCx,'a', 0); | |
| 484 | 533 | if(tmp){ |
| 485 | - cson_object_set( o, "$ENV", tmp ); | |
| 534 | + cson_object_set( o, "$APP", tmp ); | |
| 486 | 535 | } |
| 487 | 536 | tmp = cson_value_new_integer( g.json.cmdOffset ); |
| 488 | 537 | cson_object_set( o, "cmdOffset", tmp ); |
| 538 | + cson_object_set( o, "isCGI", cson_value_new_bool( g.isCGI ) ); | |
| 489 | 539 | } |
| 490 | 540 | |
| 491 | 541 | goto ok; |
| 492 | 542 | cleanup: |
| 493 | 543 | cson_value_free(v); |
| @@ -808,10 +858,11 @@ | ||
| 808 | 858 | cson_value * root = NULL; |
| 809 | 859 | JsonPageDef const * pageDef = NULL; |
| 810 | 860 | cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) ); |
| 811 | 861 | json_mode_bootstrap(); |
| 812 | 862 | cmd = json_path_part(1); |
| 863 | + /*cgi_printf("{\"cmd\":\"%s\"}\n",cmd); return;*/ | |
| 813 | 864 | pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]); |
| 814 | 865 | if( ! pageDef ){ |
| 815 | 866 | json_err( FSL_JSON_E_UNKNOWN_COMMAND, cmd, 0 ); |
| 816 | 867 | return; |
| 817 | 868 | }else if( pageDef->runMode < 0 /*CLI only*/) { |
| 818 | 869 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -254,17 +254,55 @@ | |
| 254 | ** but does not perform any authentication here. It _might_ |
| 255 | ** (haven't tested this) die with an error if an auth cookie |
| 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 ){ |
| @@ -287,15 +325,25 @@ | |
| 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,18 +350,19 @@ | |
| 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 | |
| @@ -478,16 +527,17 @@ | |
| 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); |
| @@ -808,10 +858,11 @@ | |
| 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 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -254,17 +254,55 @@ | |
| 254 | ** but does not perform any authentication here. It _might_ |
| 255 | ** (haven't tested this) die with an error if an auth cookie |
| 256 | ** is malformed. |
| 257 | */ |
| 258 | static void json_mode_bootstrap(){ |
| 259 | char const * zPath = P("PATH_INFO"); |
| 260 | g.json.isJsonMode = 1; |
| 261 | g.json.resultCode = 0; |
| 262 | g.json.cmdOffset = -1; |
| 263 | if( !g.isCGI && g.fullHttpReply ){ |
| 264 | g.isCGI = 1; |
| 265 | } |
| 266 | /*json_err( 1000, zPath, 1 ); exit(0);*/ |
| 267 | if( !zPath || !*zPath ){ |
| 268 | zPath = cson_string_cstr(cson_value_get_string(cson_cgi_getenv(&g.json.cgiCx,"e","PATH_INFO"))); |
| 269 | } |
| 270 | #if defined(NDEBUG) |
| 271 | /* avoids debug messages on stderr in JSON mode */ |
| 272 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 273 | #endif |
| 274 | if( zPath ){ |
| 275 | /* Translate fossil's PATH_INFO into cson_cgi for later |
| 276 | convenience, to help consolidate how we handle CGI/server |
| 277 | modes. |
| 278 | */ |
| 279 | char const * p = zPath; |
| 280 | char const * head = p; |
| 281 | unsigned int len = 0; |
| 282 | cson_value * piece = NULL; |
| 283 | cson_value * arV = cson_value_new_array(); |
| 284 | cson_array * ar = cson_value_get_array(arV); |
| 285 | #if 0 |
| 286 | cson_cgi_setenv( &g.json.cgiCx, "FOSSIL_PATH_INFO", cson_value_new_string(zPath,strlen(zPath)) ); |
| 287 | #endif |
| 288 | cson_cgi_setenv( &g.json.cgiCx, "COMMAND_PATH", arV ); |
| 289 | for( ;*p!='?'; ++p){ |
| 290 | if( !*p || ('/' == *p) ){ |
| 291 | if( len ) { |
| 292 | assert( head != p ); |
| 293 | piece = cson_value_new_string(head, len); |
| 294 | cson_array_append( ar, piece ); |
| 295 | len = 0; |
| 296 | } |
| 297 | if( !*p ) break; |
| 298 | head = p+1; |
| 299 | continue; |
| 300 | } |
| 301 | ++len; |
| 302 | } |
| 303 | } |
| 304 | /* g.json.reqPayload exists only to simplify some of our access to |
| 305 | the request payload. We only use this in the context of Object |
| 306 | payloads, not Arrays, strings, etc. */ |
| 307 | g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" ); |
| 308 | if( g.json.reqPayload.v ){ |
| @@ -287,15 +325,25 @@ | |
| 325 | ** Returns the ndx'th item in the PATH_INFO path, where index 0 is |
| 326 | ** the position of the "json" part of the path. Returns NULL if ndx |
| 327 | ** is out of bounds or there is no "json" path element. |
| 328 | */ |
| 329 | static char const * json_path_part(unsigned char ndx){ |
| 330 | cson_array * ar = g.isCGI |
| 331 | ? cson_value_get_array(cson_cgi_getenv(&g.json.cgiCx,"a","COMMAND_PATH")) |
| 332 | : NULL; |
| 333 | if( g.isCGI ){ |
| 334 | assert((NULL!=ar) && "Internal error."); |
| 335 | } |
| 336 | if( g.json.cmdOffset < 0 ){ |
| 337 | /* first-time setup. */ |
| 338 | short i = g.isCGI ? 0 : 1; |
| 339 | #define PARTAT cson_string_cstr( \ |
| 340 | cson_value_get_string( \ |
| 341 | cson_array_get(ar,i) \ |
| 342 | )) |
| 343 | #define NEXT (g.isCGI \ |
| 344 | ? PARTAT \ |
| 345 | : ((g.argc > i) ? g.argv[i] : NULL)) |
| 346 | char const * tok = NEXT; |
| 347 | while( tok ){ |
| 348 | if( 0==strncmp("json",tok,4) ){ |
| 349 | g.json.cmdOffset = i; |
| @@ -302,18 +350,19 @@ | |
| 350 | break; |
| 351 | } |
| 352 | ++i; |
| 353 | tok = NEXT; |
| 354 | #undef NEXT |
| 355 | #undef PARTAT |
| 356 | } |
| 357 | } |
| 358 | if( g.json.cmdOffset < 0 ){ |
| 359 | return NULL; |
| 360 | }else{ |
| 361 | ndx = g.json.cmdOffset + ndx; |
| 362 | return g.isCGI |
| 363 | ? cson_string_cstr(cson_value_get_string(cson_array_get( ar, g.json.cmdOffset + ndx ))) |
| 364 | : ((ndx < g.argc) ? g.argv[ndx] : NULL) |
| 365 | ; |
| 366 | } |
| 367 | } |
| 368 | |
| @@ -478,16 +527,17 @@ | |
| 527 | SET("payload"); |
| 528 | } |
| 529 | } |
| 530 | #undef SET |
| 531 | if(0){/*only for my own debuggering*/ |
| 532 | tmp = cson_cgi_env_get_val(&g.json.cgiCx,'a', 0); |
| 533 | if(tmp){ |
| 534 | cson_object_set( o, "$APP", tmp ); |
| 535 | } |
| 536 | tmp = cson_value_new_integer( g.json.cmdOffset ); |
| 537 | cson_object_set( o, "cmdOffset", tmp ); |
| 538 | cson_object_set( o, "isCGI", cson_value_new_bool( g.isCGI ) ); |
| 539 | } |
| 540 | |
| 541 | goto ok; |
| 542 | cleanup: |
| 543 | cson_value_free(v); |
| @@ -808,10 +858,11 @@ | |
| 858 | cson_value * root = NULL; |
| 859 | JsonPageDef const * pageDef = NULL; |
| 860 | cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) ); |
| 861 | json_mode_bootstrap(); |
| 862 | cmd = json_path_part(1); |
| 863 | /*cgi_printf("{\"cmd\":\"%s\"}\n",cmd); return;*/ |
| 864 | pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]); |
| 865 | if( ! pageDef ){ |
| 866 | json_err( FSL_JSON_E_UNKNOWN_COMMAND, cmd, 0 ); |
| 867 | return; |
| 868 | }else if( pageDef->runMode < 0 /*CLI only*/) { |
| 869 |