Fossil SCM
Add support for POST in JSON over HTTP. Test /json/cap with various ways of delivering an authToken to cover the rest of the Authentication category basic functionality. NOTE that supplying the authToken in the POSTed JSON request envelope does not appear to work. Passing it in a cookie or in a GET parameter does work as expected.
Commit
479aadb1d2645601aa8095beec5c26113a181650
Parent
f28e771369fe2e3…
1 file changed
+71
-7
+71
-7
| --- test/json.test | ||
| +++ test/json.test | ||
| @@ -70,10 +70,57 @@ | ||
| 70 | 70 | set JR [::json::json2dict $body] |
| 71 | 71 | } |
| 72 | 72 | return $status |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | + | |
| 76 | +# Use the HTTP interface to POST a JSON API URL. Sets the globals | |
| 77 | +# RESULT to the HTTP response body, and JR to a Tcl dict conversion of | |
| 78 | +# the response body. | |
| 79 | +# | |
| 80 | +# Returns the status code from the HTTP header. | |
| 81 | +proc fossil_post_json {url data {cookie "Muppet=Monster"} args} { | |
| 82 | + global RESULT JR | |
| 83 | + | |
| 84 | + # set up a full GET or POST HTTP request | |
| 85 | + set len [string length $data] | |
| 86 | + if {$len > 0} { | |
| 87 | + set request [subst {POST $url HTTP/1.0\r | |
| 88 | +Host: localhost\r | |
| 89 | +User-Agent: Fossil-Test\r | |
| 90 | +Cookie: $cookie\r | |
| 91 | +Content-Type: application/json | |
| 92 | +Content-Length $len | |
| 93 | +\r | |
| 94 | +$data}] | |
| 95 | + } else { | |
| 96 | + set request [subst {GET $url HTTP/1.0\r | |
| 97 | +Host: localhost\r | |
| 98 | +User-Agent: Fossil-Test\r | |
| 99 | +Cookie: $cookie\r | |
| 100 | +\r | |
| 101 | +}] | |
| 102 | + } | |
| 103 | + | |
| 104 | + # handle the actual request | |
| 105 | + flush stdout | |
| 106 | + #exec $fossilexe | |
| 107 | + set RESULT [fossil_maybe_answer $request http {*}$args] | |
| 108 | + | |
| 109 | + # separate HTTP headers from body | |
| 110 | + regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body | |
| 111 | + regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg | |
| 112 | + if {$status eq "200"} { | |
| 113 | + if {[string length $body] > 0} { | |
| 114 | + set JR [::json::json2dict $body] | |
| 115 | + } else { | |
| 116 | + set JR "" | |
| 117 | + } | |
| 118 | + } | |
| 119 | + return $status | |
| 120 | +} | |
| 121 | + | |
| 75 | 122 | |
| 76 | 123 | # Inspect a dict for keys it must have and keys it must not have |
| 77 | 124 | proc test_dict_keys {testname D okfields badfields} { |
| 78 | 125 | set i 1 |
| 79 | 126 | foreach f $okfields { |
| @@ -234,19 +281,36 @@ | ||
| 234 | 281 | "authToken":"[dict get $AuthAnon authToken]" |
| 235 | 282 | } |
| 236 | 283 | }] |
| 237 | 284 | fossil_json --json-input anon-2 |
| 238 | 285 | test_json_envelope_ok json-cap-env |
| 239 | -# No point checking any other flags, setup implies all, and all are | |
| 240 | -# moot from CLI. | |
| 241 | 286 | test json-cap-CLI {[dict get $JR payload permissionFlags setup]} |
| 242 | 287 | |
| 243 | -test TODO-json-post-authentication false knownBug | |
| 244 | -#TODO: implement support for POST with JSON payload from file | |
| 245 | -#fossil_http_post_json /json anon-2 | |
| 246 | -#test_json_envelope_ok json-cap-http-env | |
| 247 | -#test json-cap-http {![dict get $JR payload permissionFlags setup]} | |
| 288 | +# json cap via POST with authToken in request envelope | |
| 289 | +set anon2 [read_file anon-2] | |
| 290 | +fossil_post_json "/json/cap" $anon2 | |
| 291 | +test json-cap-POSTenv-env-0 {[string length $JR] > 0} | |
| 292 | +test_json_envelope_ok json-cap-POSTenv-env | |
| 293 | +test json-cap-POSTenv-name {[dict get $JR payload name] eq "anonymous"} knownBug | |
| 294 | +test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]} | |
| 295 | + | |
| 296 | + | |
| 297 | +# json cap via GET with authToken in Cookie header | |
| 298 | +fossil_post_json "/json/cap" {} $AnonCookie | |
| 299 | +test json-cap-GETcookie-env-0 {[string length $JR] > 0} | |
| 300 | +test_json_envelope_ok json-cap-GETcookie-env | |
| 301 | +test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} | |
| 302 | +test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} | |
| 303 | + | |
| 304 | + | |
| 305 | +# json cap via GET with authToken in a parameter | |
| 306 | +fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {} | |
| 307 | +test json-cap-GETcookie-env-0 {[string length $JR] > 0} | |
| 308 | +test_json_envelope_ok json-cap-GETcookie-env | |
| 309 | +test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} | |
| 310 | +test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} | |
| 311 | + | |
| 248 | 312 | |
| 249 | 313 | # whoami |
| 250 | 314 | # via CLI with no auth token supplied |
| 251 | 315 | fossil_json whoami |
| 252 | 316 | test_json_envelope_ok json-whoami-cli-env |
| 253 | 317 |
| --- test/json.test | |
| +++ test/json.test | |
| @@ -70,10 +70,57 @@ | |
| 70 | set JR [::json::json2dict $body] |
| 71 | } |
| 72 | return $status |
| 73 | } |
| 74 | |
| 75 | |
| 76 | # Inspect a dict for keys it must have and keys it must not have |
| 77 | proc test_dict_keys {testname D okfields badfields} { |
| 78 | set i 1 |
| 79 | foreach f $okfields { |
| @@ -234,19 +281,36 @@ | |
| 234 | "authToken":"[dict get $AuthAnon authToken]" |
| 235 | } |
| 236 | }] |
| 237 | fossil_json --json-input anon-2 |
| 238 | test_json_envelope_ok json-cap-env |
| 239 | # No point checking any other flags, setup implies all, and all are |
| 240 | # moot from CLI. |
| 241 | test json-cap-CLI {[dict get $JR payload permissionFlags setup]} |
| 242 | |
| 243 | test TODO-json-post-authentication false knownBug |
| 244 | #TODO: implement support for POST with JSON payload from file |
| 245 | #fossil_http_post_json /json anon-2 |
| 246 | #test_json_envelope_ok json-cap-http-env |
| 247 | #test json-cap-http {![dict get $JR payload permissionFlags setup]} |
| 248 | |
| 249 | # whoami |
| 250 | # via CLI with no auth token supplied |
| 251 | fossil_json whoami |
| 252 | test_json_envelope_ok json-whoami-cli-env |
| 253 |
| --- test/json.test | |
| +++ test/json.test | |
| @@ -70,10 +70,57 @@ | |
| 70 | set JR [::json::json2dict $body] |
| 71 | } |
| 72 | return $status |
| 73 | } |
| 74 | |
| 75 | |
| 76 | # Use the HTTP interface to POST a JSON API URL. Sets the globals |
| 77 | # RESULT to the HTTP response body, and JR to a Tcl dict conversion of |
| 78 | # the response body. |
| 79 | # |
| 80 | # Returns the status code from the HTTP header. |
| 81 | proc fossil_post_json {url data {cookie "Muppet=Monster"} args} { |
| 82 | global RESULT JR |
| 83 | |
| 84 | # set up a full GET or POST HTTP request |
| 85 | set len [string length $data] |
| 86 | if {$len > 0} { |
| 87 | set request [subst {POST $url HTTP/1.0\r |
| 88 | Host: localhost\r |
| 89 | User-Agent: Fossil-Test\r |
| 90 | Cookie: $cookie\r |
| 91 | Content-Type: application/json |
| 92 | Content-Length $len |
| 93 | \r |
| 94 | $data}] |
| 95 | } else { |
| 96 | set request [subst {GET $url HTTP/1.0\r |
| 97 | Host: localhost\r |
| 98 | User-Agent: Fossil-Test\r |
| 99 | Cookie: $cookie\r |
| 100 | \r |
| 101 | }] |
| 102 | } |
| 103 | |
| 104 | # handle the actual request |
| 105 | flush stdout |
| 106 | #exec $fossilexe |
| 107 | set RESULT [fossil_maybe_answer $request http {*}$args] |
| 108 | |
| 109 | # separate HTTP headers from body |
| 110 | regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body |
| 111 | regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg |
| 112 | if {$status eq "200"} { |
| 113 | if {[string length $body] > 0} { |
| 114 | set JR [::json::json2dict $body] |
| 115 | } else { |
| 116 | set JR "" |
| 117 | } |
| 118 | } |
| 119 | return $status |
| 120 | } |
| 121 | |
| 122 | |
| 123 | # Inspect a dict for keys it must have and keys it must not have |
| 124 | proc test_dict_keys {testname D okfields badfields} { |
| 125 | set i 1 |
| 126 | foreach f $okfields { |
| @@ -234,19 +281,36 @@ | |
| 281 | "authToken":"[dict get $AuthAnon authToken]" |
| 282 | } |
| 283 | }] |
| 284 | fossil_json --json-input anon-2 |
| 285 | test_json_envelope_ok json-cap-env |
| 286 | test json-cap-CLI {[dict get $JR payload permissionFlags setup]} |
| 287 | |
| 288 | # json cap via POST with authToken in request envelope |
| 289 | set anon2 [read_file anon-2] |
| 290 | fossil_post_json "/json/cap" $anon2 |
| 291 | test json-cap-POSTenv-env-0 {[string length $JR] > 0} |
| 292 | test_json_envelope_ok json-cap-POSTenv-env |
| 293 | test json-cap-POSTenv-name {[dict get $JR payload name] eq "anonymous"} knownBug |
| 294 | test json-cap-POSTenv-notsetup {![dict get $JR payload permissionFlags setup]} |
| 295 | |
| 296 | |
| 297 | # json cap via GET with authToken in Cookie header |
| 298 | fossil_post_json "/json/cap" {} $AnonCookie |
| 299 | test json-cap-GETcookie-env-0 {[string length $JR] > 0} |
| 300 | test_json_envelope_ok json-cap-GETcookie-env |
| 301 | test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} |
| 302 | test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} |
| 303 | |
| 304 | |
| 305 | # json cap via GET with authToken in a parameter |
| 306 | fossil_post_json "/json/cap?authToken=[dict get $AuthAnon authToken]" {} |
| 307 | test json-cap-GETcookie-env-0 {[string length $JR] > 0} |
| 308 | test_json_envelope_ok json-cap-GETcookie-env |
| 309 | test json-cap-GETcookie-name {[dict get $JR payload name] eq "anonymous"} |
| 310 | test json-cap-GETcookie-notsetup {![dict get $JR payload permissionFlags setup]} |
| 311 | |
| 312 | |
| 313 | # whoami |
| 314 | # via CLI with no auth token supplied |
| 315 | fossil_json whoami |
| 316 | test_json_envelope_ok json-whoami-cli-env |
| 317 |