Fossil SCM
minor cleanups to the json "command path" handling.
Commit
2dcc2397b5802610c16ced0809045bb27a7fb44b
Parent
c5fbcced800163e…
2 files changed
+43
-25
+1
-1
+43
-25
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -76,12 +76,14 @@ | ||
| 76 | 76 | /* |
| 77 | 77 | ** Holds keys used for various JSON API properties. |
| 78 | 78 | */ |
| 79 | 79 | static const struct FossilJsonKeys_{ |
| 80 | 80 | char const * authToken; |
| 81 | + char const * commandPath; | |
| 81 | 82 | } FossilJsonKeys = { |
| 82 | - "authToken" /*authToken*/ | |
| 83 | + "authToken" /*authToken*/, | |
| 84 | + "COMMAND_PATH" /*commandPath*/ | |
| 83 | 85 | }; |
| 84 | 86 | |
| 85 | 87 | /* |
| 86 | 88 | ** Given a FossilJsonCodes value, it returns a string suitable for use |
| 87 | 89 | ** as a resultText string. Returns some unspecified string if errCode |
| @@ -255,45 +257,56 @@ | ||
| 255 | 257 | ** (haven't tested this) die with an error if an auth cookie |
| 256 | 258 | ** is malformed. |
| 257 | 259 | */ |
| 258 | 260 | static void json_mode_bootstrap(){ |
| 259 | 261 | char const * zPath = P("PATH_INFO"); |
| 262 | + cson_value * pathSplit = | |
| 263 | + cson_cgi_getenv(&g.json.cgiCx,"e","PATH_INFO_SPLIT"); | |
| 260 | 264 | g.json.isJsonMode = 1; |
| 261 | 265 | g.json.resultCode = 0; |
| 262 | 266 | g.json.cmdOffset = -1; |
| 263 | 267 | if( !g.isCGI && g.fullHttpReply ){ |
| 264 | 268 | g.isCGI = 1; |
| 265 | 269 | } |
| 266 | 270 | /*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 | 271 | #if defined(NDEBUG) |
| 271 | 272 | /* avoids debug messages on stderr in JSON mode */ |
| 272 | 273 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 273 | 274 | #endif |
| 274 | - if( zPath ){ | |
| 275 | + | |
| 276 | + /* | |
| 277 | + The following if/else block translates the PATH_INFO path into an | |
| 278 | + internal list so that we can simplify command dispatching later | |
| 279 | + on. | |
| 280 | + */ | |
| 281 | + if( pathSplit ){ | |
| 282 | + /* cson_cgi already did this, so let's just re-use it. This does | |
| 283 | + not happen in "plain server" mode, but does in CGI mode. | |
| 284 | + */ | |
| 285 | + cson_cgi_setenv( &g.json.cgiCx, | |
| 286 | + FossilJsonKeys.commandPath, | |
| 287 | + pathSplit ); | |
| 288 | + }else if( zPath ){ | |
| 275 | 289 | /* Translate fossil's PATH_INFO into cson_cgi for later |
| 276 | 290 | convenience, to help consolidate how we handle CGI/server |
| 277 | - modes. | |
| 291 | + modes. This block is hit when running in plain server mode. | |
| 278 | 292 | */ |
| 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 ); | |
| 293 | + char const * p = zPath; /* current byte */ | |
| 294 | + char const * head = p; /* current start-of-token */ | |
| 295 | + unsigned int len = 0; /* current token's lengh */ | |
| 296 | + cson_value * arV = cson_value_new_array(); /* value to store path in */ | |
| 297 | + cson_array * ar = cson_value_get_array(arV); /* the real array object */ | |
| 298 | + cson_cgi_setenv( &g.json.cgiCx, | |
| 299 | + FossilJsonKeys.commandPath, | |
| 300 | + arV ); | |
| 289 | 301 | for( ;*p!='?'; ++p){ |
| 290 | 302 | if( !*p || ('/' == *p) ){ |
| 291 | 303 | if( len ) { |
| 304 | + cson_value * part; | |
| 292 | 305 | assert( head != p ); |
| 293 | - piece = cson_value_new_string(head, len); | |
| 294 | - cson_array_append( ar, piece ); | |
| 306 | + part = cson_value_new_string(head, len); | |
| 307 | + cson_array_append( ar, part ); | |
| 295 | 308 | len = 0; |
| 296 | 309 | } |
| 297 | 310 | if( !*p ) break; |
| 298 | 311 | head = p+1; |
| 299 | 312 | continue; |
| @@ -300,12 +313,12 @@ | ||
| 300 | 313 | } |
| 301 | 314 | ++len; |
| 302 | 315 | } |
| 303 | 316 | } |
| 304 | 317 | /* 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. */ | |
| 318 | + the request payload. We currently only use this in the context of | |
| 319 | + Object payloads, not Arrays, strings, etc. */ | |
| 307 | 320 | g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" ); |
| 308 | 321 | if( g.json.reqPayload.v ){ |
| 309 | 322 | g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v ) |
| 310 | 323 | /* g.json.reqPayload.o may legally be NULL, which means only that |
| 311 | 324 | g.json.reqPayload.v is-not-a Object. |
| @@ -320,17 +333,22 @@ | ||
| 320 | 333 | } |
| 321 | 334 | |
| 322 | 335 | } |
| 323 | 336 | |
| 324 | 337 | /* |
| 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. | |
| 338 | +** Returns the ndx'th item in the "command path", where index 0 is the | |
| 339 | +** position of the "json" part of the path. Returns NULL if ndx is out | |
| 340 | +** of bounds or there is no "json" path element. | |
| 341 | +** | |
| 342 | +** In CLI mode the "path" is the list of arguments (skipping argv[0]). | |
| 343 | +** In server/CGI modes the path is the PATH_INFO. | |
| 328 | 344 | */ |
| 329 | 345 | static char const * json_path_part(unsigned char ndx){ |
| 330 | 346 | cson_array * ar = g.isCGI |
| 331 | - ? cson_value_get_array(cson_cgi_getenv(&g.json.cgiCx,"a","COMMAND_PATH")) | |
| 347 | + ? cson_value_get_array(cson_cgi_getenv(&g.json.cgiCx, | |
| 348 | + "a", | |
| 349 | + FossilJsonKeys.commandPath)) | |
| 332 | 350 | : NULL; |
| 333 | 351 | if( g.isCGI ){ |
| 334 | 352 | assert((NULL!=ar) && "Internal error."); |
| 335 | 353 | } |
| 336 | 354 | if( g.json.cmdOffset < 0 ){ |
| @@ -906,14 +924,14 @@ | ||
| 906 | 924 | unsigned int n; |
| 907 | 925 | int rc = 1002; |
| 908 | 926 | cson_value * payload = NULL; |
| 909 | 927 | JsonPageDef const * pageDef; |
| 910 | 928 | json_mode_bootstrap(); |
| 911 | - db_find_and_open_repository(0, 0); | |
| 912 | 929 | if( g.argc<3 ){ |
| 913 | 930 | goto usage; |
| 914 | 931 | } |
| 932 | + db_find_and_open_repository(0, 0); | |
| 915 | 933 | cmd = json_path_part(1); |
| 916 | 934 | n = cmd ? strlen(cmd) : 0; |
| 917 | 935 | if( n==0 ){ |
| 918 | 936 | goto usage; |
| 919 | 937 | } |
| 920 | 938 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -76,12 +76,14 @@ | |
| 76 | /* |
| 77 | ** Holds keys used for various JSON API properties. |
| 78 | */ |
| 79 | static const struct FossilJsonKeys_{ |
| 80 | char const * authToken; |
| 81 | } FossilJsonKeys = { |
| 82 | "authToken" /*authToken*/ |
| 83 | }; |
| 84 | |
| 85 | /* |
| 86 | ** Given a FossilJsonCodes value, it returns a string suitable for use |
| 87 | ** as a resultText string. Returns some unspecified string if errCode |
| @@ -255,45 +257,56 @@ | |
| 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,12 +313,12 @@ | |
| 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 ){ |
| 309 | g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v ) |
| 310 | /* g.json.reqPayload.o may legally be NULL, which means only that |
| 311 | g.json.reqPayload.v is-not-a Object. |
| @@ -320,17 +333,22 @@ | |
| 320 | } |
| 321 | |
| 322 | } |
| 323 | |
| 324 | /* |
| 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 ){ |
| @@ -906,14 +924,14 @@ | |
| 906 | unsigned int n; |
| 907 | int rc = 1002; |
| 908 | cson_value * payload = NULL; |
| 909 | JsonPageDef const * pageDef; |
| 910 | json_mode_bootstrap(); |
| 911 | db_find_and_open_repository(0, 0); |
| 912 | if( g.argc<3 ){ |
| 913 | goto usage; |
| 914 | } |
| 915 | cmd = json_path_part(1); |
| 916 | n = cmd ? strlen(cmd) : 0; |
| 917 | if( n==0 ){ |
| 918 | goto usage; |
| 919 | } |
| 920 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -76,12 +76,14 @@ | |
| 76 | /* |
| 77 | ** Holds keys used for various JSON API properties. |
| 78 | */ |
| 79 | static const struct FossilJsonKeys_{ |
| 80 | char const * authToken; |
| 81 | char const * commandPath; |
| 82 | } FossilJsonKeys = { |
| 83 | "authToken" /*authToken*/, |
| 84 | "COMMAND_PATH" /*commandPath*/ |
| 85 | }; |
| 86 | |
| 87 | /* |
| 88 | ** Given a FossilJsonCodes value, it returns a string suitable for use |
| 89 | ** as a resultText string. Returns some unspecified string if errCode |
| @@ -255,45 +257,56 @@ | |
| 257 | ** (haven't tested this) die with an error if an auth cookie |
| 258 | ** is malformed. |
| 259 | */ |
| 260 | static void json_mode_bootstrap(){ |
| 261 | char const * zPath = P("PATH_INFO"); |
| 262 | cson_value * pathSplit = |
| 263 | cson_cgi_getenv(&g.json.cgiCx,"e","PATH_INFO_SPLIT"); |
| 264 | g.json.isJsonMode = 1; |
| 265 | g.json.resultCode = 0; |
| 266 | g.json.cmdOffset = -1; |
| 267 | if( !g.isCGI && g.fullHttpReply ){ |
| 268 | g.isCGI = 1; |
| 269 | } |
| 270 | /*json_err( 1000, zPath, 1 ); exit(0);*/ |
| 271 | #if defined(NDEBUG) |
| 272 | /* avoids debug messages on stderr in JSON mode */ |
| 273 | sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0); |
| 274 | #endif |
| 275 | |
| 276 | /* |
| 277 | The following if/else block translates the PATH_INFO path into an |
| 278 | internal list so that we can simplify command dispatching later |
| 279 | on. |
| 280 | */ |
| 281 | if( pathSplit ){ |
| 282 | /* cson_cgi already did this, so let's just re-use it. This does |
| 283 | not happen in "plain server" mode, but does in CGI mode. |
| 284 | */ |
| 285 | cson_cgi_setenv( &g.json.cgiCx, |
| 286 | FossilJsonKeys.commandPath, |
| 287 | pathSplit ); |
| 288 | }else if( zPath ){ |
| 289 | /* Translate fossil's PATH_INFO into cson_cgi for later |
| 290 | convenience, to help consolidate how we handle CGI/server |
| 291 | modes. This block is hit when running in plain server mode. |
| 292 | */ |
| 293 | char const * p = zPath; /* current byte */ |
| 294 | char const * head = p; /* current start-of-token */ |
| 295 | unsigned int len = 0; /* current token's lengh */ |
| 296 | cson_value * arV = cson_value_new_array(); /* value to store path in */ |
| 297 | cson_array * ar = cson_value_get_array(arV); /* the real array object */ |
| 298 | cson_cgi_setenv( &g.json.cgiCx, |
| 299 | FossilJsonKeys.commandPath, |
| 300 | arV ); |
| 301 | for( ;*p!='?'; ++p){ |
| 302 | if( !*p || ('/' == *p) ){ |
| 303 | if( len ) { |
| 304 | cson_value * part; |
| 305 | assert( head != p ); |
| 306 | part = cson_value_new_string(head, len); |
| 307 | cson_array_append( ar, part ); |
| 308 | len = 0; |
| 309 | } |
| 310 | if( !*p ) break; |
| 311 | head = p+1; |
| 312 | continue; |
| @@ -300,12 +313,12 @@ | |
| 313 | } |
| 314 | ++len; |
| 315 | } |
| 316 | } |
| 317 | /* g.json.reqPayload exists only to simplify some of our access to |
| 318 | the request payload. We currently only use this in the context of |
| 319 | Object payloads, not Arrays, strings, etc. */ |
| 320 | g.json.reqPayload.v = cson_cgi_getenv( &g.json.cgiCx, "p", "payload" ); |
| 321 | if( g.json.reqPayload.v ){ |
| 322 | g.json.reqPayload.o = cson_value_get_object( g.json.reqPayload.v ) |
| 323 | /* g.json.reqPayload.o may legally be NULL, which means only that |
| 324 | g.json.reqPayload.v is-not-a Object. |
| @@ -320,17 +333,22 @@ | |
| 333 | } |
| 334 | |
| 335 | } |
| 336 | |
| 337 | /* |
| 338 | ** Returns the ndx'th item in the "command path", where index 0 is the |
| 339 | ** position of the "json" part of the path. Returns NULL if ndx is out |
| 340 | ** of bounds or there is no "json" path element. |
| 341 | ** |
| 342 | ** In CLI mode the "path" is the list of arguments (skipping argv[0]). |
| 343 | ** In server/CGI modes the path is the PATH_INFO. |
| 344 | */ |
| 345 | static char const * json_path_part(unsigned char ndx){ |
| 346 | cson_array * ar = g.isCGI |
| 347 | ? cson_value_get_array(cson_cgi_getenv(&g.json.cgiCx, |
| 348 | "a", |
| 349 | FossilJsonKeys.commandPath)) |
| 350 | : NULL; |
| 351 | if( g.isCGI ){ |
| 352 | assert((NULL!=ar) && "Internal error."); |
| 353 | } |
| 354 | if( g.json.cmdOffset < 0 ){ |
| @@ -906,14 +924,14 @@ | |
| 924 | unsigned int n; |
| 925 | int rc = 1002; |
| 926 | cson_value * payload = NULL; |
| 927 | JsonPageDef const * pageDef; |
| 928 | json_mode_bootstrap(); |
| 929 | if( g.argc<3 ){ |
| 930 | goto usage; |
| 931 | } |
| 932 | db_find_and_open_repository(0, 0); |
| 933 | cmd = json_path_part(1); |
| 934 | n = cmd ? strlen(cmd) : 0; |
| 935 | if( n==0 ){ |
| 936 | goto usage; |
| 937 | } |
| 938 |
+1
-1
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -116,11 +116,11 @@ | ||
| 116 | 116 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ |
| 117 | 117 | int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ |
| 118 | 118 | int *aCommitFile; /* Array of files to be committed */ |
| 119 | 119 | int markPrivate; /* All new artifacts are private if true */ |
| 120 | 120 | int clockSkewSeen; /* True if clocks on client and server out of sync */ |
| 121 | - int isCGI; /* True if running in HTTP/CGI mode, else assume CLI. */ | |
| 121 | + int isCGI; /* True if running in server/CGI modes, else assume CLI. */ | |
| 122 | 122 | |
| 123 | 123 | int urlIsFile; /* True if a "file:" url */ |
| 124 | 124 | int urlIsHttps; /* True if a "https:" url */ |
| 125 | 125 | int urlIsSsh; /* True if an "ssh:" url */ |
| 126 | 126 | char *urlName; /* Hostname for http: or filename for file: */ |
| 127 | 127 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -116,11 +116,11 @@ | |
| 116 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ |
| 117 | int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ |
| 118 | int *aCommitFile; /* Array of files to be committed */ |
| 119 | int markPrivate; /* All new artifacts are private if true */ |
| 120 | int clockSkewSeen; /* True if clocks on client and server out of sync */ |
| 121 | int isCGI; /* True if running in HTTP/CGI mode, else assume CLI. */ |
| 122 | |
| 123 | int urlIsFile; /* True if a "file:" url */ |
| 124 | int urlIsHttps; /* True if a "https:" url */ |
| 125 | int urlIsSsh; /* True if an "ssh:" url */ |
| 126 | char *urlName; /* Hostname for http: or filename for file: */ |
| 127 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -116,11 +116,11 @@ | |
| 116 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ |
| 117 | int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ |
| 118 | int *aCommitFile; /* Array of files to be committed */ |
| 119 | int markPrivate; /* All new artifacts are private if true */ |
| 120 | int clockSkewSeen; /* True if clocks on client and server out of sync */ |
| 121 | int isCGI; /* True if running in server/CGI modes, else assume CLI. */ |
| 122 | |
| 123 | int urlIsFile; /* True if a "file:" url */ |
| 124 | int urlIsHttps; /* True if a "https:" url */ |
| 125 | int urlIsSsh; /* True if an "ssh:" url */ |
| 126 | char *urlName; /* Hostname for http: or filename for file: */ |
| 127 |