Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Experimental changes to get JSON tests passing. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | jsonTestsPass |
| Files: | files | file ages | folders |
| SHA3-256: |
2e4238368ea5093773a0849946d6ce54 |
| User & Date: | mistachkin 2020-06-11 22:38:27.207 |
Context
|
2020-06-11
| ||
| 23:06 | More JSON test adjustments. ... (check-in: ad0679cabf user: mistachkin tags: jsonTestsPass) | |
| 22:38 | Experimental changes to get JSON tests passing. ... (check-in: 2e4238368e user: mistachkin tags: jsonTestsPass) | |
| 21:03 | In the Markdown formatter, bring emphasis markup into closer alignment with the CommonMark spec. In particular, this should allow underscores in the middle of identifiers to be rendered correctly without escapes. ... (check-in: 37806e85d2 user: drh tags: trunk) | |
Changes
Changes to src/db.c.
| ︙ | ︙ | |||
76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( 0, z, 1 );
}
else
#endif /* FOSSIL_ENABLE_JSON */
if( g.xferPanic && g.cgiOutput==1 ){
cgi_reset_content();
@ error Database\serror:\s%F(z)
| > | 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
va_list ap;
char *z;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
if( !json_is_main_boostrapped() ) json_main_bootstrap();
json_err( 0, z, 1 );
}
else
#endif /* FOSSIL_ENABLE_JSON */
if( g.xferPanic && g.cgiOutput==1 ){
cgi_reset_content();
@ error Database\serror:\s%F(z)
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
** caller.
*/
cson_value * json_req_payload_get(char const *pKey){
return g.json.reqPayload.o
? cson_object_get(g.json.reqPayload.o,pKey)
: NULL;
}
/*
** Initializes some JSON bits which need to be initialized relatively
** early on. It should only be called from cgi_init() or
** json_cmd_top() (early on in those functions).
**
** Initializes g.json.gc and g.json.param. This code does not (and
| > > > > > > > > > > > | 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
** caller.
*/
cson_value * json_req_payload_get(char const *pKey){
return g.json.reqPayload.o
? cson_object_get(g.json.reqPayload.o,pKey)
: NULL;
}
/*
** Returns non-zero if the json_main_bootstrap() function has already
** been called. In general, this function should be used sparingly,
** e.g. from low-level support functions like fossil_warning() where
** there is genuine uncertainty about whether (or not) the JSON setup
** has already been called.
*/
int json_is_main_boostrapped(){
return ((g.json.gc.v != NULL) && (g.json.gc.a != NULL));
}
/*
** Initializes some JSON bits which need to be initialized relatively
** early on. It should only be called from cgi_init() or
** json_cmd_top() (early on in those functions).
**
** Initializes g.json.gc and g.json.param. This code does not (and
|
| ︙ | ︙ | |||
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 |
cgi_printf("%s(",g.json.jsonp);
}
cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt );
if( g.json.jsonp ){
cgi_append_content(")",1);
}
}
}else{
json_send_response(resp);
}
cson_value_free(resp);
}
/*
| > | 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 |
cgi_printf("%s(",g.json.jsonp);
}
cson_output( resp, cson_data_dest_cgi, NULL, &g.json.outOpt );
if( g.json.jsonp ){
cgi_append_content(")",1);
}
}
cgi_reply();
}else{
json_send_response(resp);
}
cson_value_free(resp);
}
/*
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 |
false. This changes how errors are
reported. In JSON mode we try to
always output JSON-form error
responses and always (in CGI mode)
exit() with code 0 to avoid an HTTP
500 error.
*/
int resultCode; /* used for passing back specific codes
** from /json callbacks. */
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
cson_output_opt outOpt; /* formatting options for JSON mode. */
cson_value *authToken; /* authentication token */
const char *jsonp; /* Name of JSONP function wrapper. */
unsigned char dispatchDepth /* Tells JSON command dispatching
| > > > | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
false. This changes how errors are
reported. In JSON mode we try to
always output JSON-form error
responses and always (in CGI mode)
exit() with code 0 to avoid an HTTP
500 error.
*/
int preserveRc; /* Do not convert error codes into 0.
* This is primarily intended for use
* by the test suite. */
int resultCode; /* used for passing back specific codes
** from /json callbacks. */
int errorDetailParanoia; /* 0=full error codes, 1=%10, 2=%100, 3=%1000 */
cson_output_opt outOpt; /* formatting options for JSON mode. */
cson_value *authToken; /* authentication token */
const char *jsonp; /* Name of JSONP function wrapper. */
unsigned char dispatchDepth /* Tells JSON command dispatching
|
| ︙ | ︙ | |||
744 745 746 747 748 749 750 751 752 753 754 755 756 757 |
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
g.fCgiTrace = find_option("cgitrace", 0, 0)!=0;
g.fSshClient = 0;
g.zSshCmd = 0;
if( g.fSqlTrace ) g.fSqlStats = 1;
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
#ifdef FOSSIL_ENABLE_TH1_HOOKS
g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
#endif
g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|
g.fHttpTrace|g.fCgiTrace;
g.zHttpAuth = 0;
| > > > | 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 |
g.fSqlStats = find_option("sqlstats", 0, 0)!=0;
g.fSystemTrace = find_option("systemtrace", 0, 0)!=0;
g.fSshTrace = find_option("sshtrace", 0, 0)!=0;
g.fCgiTrace = find_option("cgitrace", 0, 0)!=0;
g.fSshClient = 0;
g.zSshCmd = 0;
if( g.fSqlTrace ) g.fSqlStats = 1;
#ifdef FOSSIL_ENABLE_JSON
g.json.preserveRc = find_option("json-preserve-rc", 0, 0)!=0;
#endif
g.fHttpTrace = find_option("httptrace", 0, 0)!=0;
#ifdef FOSSIL_ENABLE_TH1_HOOKS
g.fNoThHook = find_option("no-th-hook", 0, 0)!=0;
#endif
g.fAnyTrace = g.fSqlTrace|g.fSystemTrace|g.fSshTrace|
g.fHttpTrace|g.fCgiTrace;
g.zHttpAuth = 0;
|
| ︙ | ︙ |
Changes to src/printf.c.
| ︙ | ︙ | |||
1074 1075 1076 1077 1078 1079 1080 1081 |
/*
** Write error message output
*/
static int fossil_print_error(int rc, const char *z){
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
json_err( 0, z, 1 );
| > | | 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 |
/*
** Write error message output
*/
static int fossil_print_error(int rc, const char *z){
#ifdef FOSSIL_ENABLE_JSON
if( g.json.isJsonMode ){
if( !json_is_main_boostrapped() ) json_main_bootstrap();
json_err( 0, z, 1 );
if( g.isHTTP && !g.json.preserveRc ){
rc = 0 /* avoid HTTP 500 */;
}
}
else
#endif
if( g.cgiOutput==1 && g.db ){
g.cgiOutput = 2;
|
| ︙ | ︙ | |||
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 |
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("warning: %s", z);
#ifdef FOSSIL_ENABLE_JSON
if(g.json.isJsonMode){
json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
}else
#endif
{
if( g.cgiOutput==1 ){
cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
}else{
| > > > > > > | 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 |
char *z;
va_list ap;
va_start(ap, zFormat);
z = vmprintf(zFormat, ap);
va_end(ap);
fossil_errorlog("warning: %s", z);
#ifdef FOSSIL_ENABLE_JSON
/*
** Avoid calling into the JSON support subsystem if it
** has not yet been initialized, e.g. early SQLite log
** messages, etc.
*/
if(g.json.isJsonMode){
if( !json_is_main_boostrapped() ) json_main_bootstrap();
json_warn( FSL_JSON_W_UNKNOWN, "%s", z );
}else
#endif
{
if( g.cgiOutput==1 ){
cgi_printf("<p class=\"generalError\">\n%h\n</p>\n", z);
}else{
|
| ︙ | ︙ |
Changes to test/json.test.
| ︙ | ︙ | |||
73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# the response body.
#
# Returns the status code from the HTTP header.
proc fossil_http_json {url {cookie "Muppet=Monster"} args} {
global RESULT JR
set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie"
set RESULT [fossil_maybe_answer $request http {*}$args]
regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
if {$status eq "200"} {
set JR [json2dict $body]
}
return $status
}
| > | 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# the response body.
#
# Returns the status code from the HTTP header.
proc fossil_http_json {url {cookie "Muppet=Monster"} args} {
global RESULT JR
set request "GET $url HTTP/1.1\r\nHost: localhost\r\nUser-Agent: Fossil-http-json\r\nCookie: $cookie"
set RESULT [fossil_maybe_answer $request http {*}$args]
set head ""; set status "--NO_MATCH--"
regexp {(?w)(.*)^\s*$(.*)} $RESULT dummy head body
regexp {^HTTP\S+\s+(\d\d\d)\s+(.*)$} $head dummy status msg
if {$status eq "200"} {
set JR [json2dict $body]
}
return $status
}
|
| ︙ | ︙ | |||
168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
test_dict_keys $testname [dict get $::JR payload] $okfields $badfields
}
#### VERSION AKA HAI
# The JSON API generally assumes we have a respository, so let it have one.
test_setup
# Check for basic envelope fields in the result with an error
fossil_json -expectError
test_json_envelope json-enverr [concat resultCode fossil timestamp \
resultText command procTimeUs procTimeMs] {}
test json-enverr-rc-1 {[dict get $JR resultCode] eq "FOSSIL-3002"}
| > > > | 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
test_dict_keys $testname [dict get $::JR payload] $okfields $badfields
}
#### VERSION AKA HAI
# The JSON API generally assumes we have a respository, so let it have one.
test_setup
# Stop backoffice from running during this test as it can cause hangs.
fossil settings backoffice-disable 1
# Check for basic envelope fields in the result with an error
fossil_json -expectError
test_json_envelope json-enverr [concat resultCode fossil timestamp \
resultText command procTimeUs procTimeMs] {}
test json-enverr-rc-1 {[dict get $JR resultCode] eq "FOSSIL-3002"}
|
| ︙ | ︙ | |||
673 674 675 676 677 678 679 | # which writes something (timeline creates a temp table). The "repo # is not writable" error comes back as HTML. i don't know if the # error happens before we have made the determination that the app is # in JSON mode or if the error handling is incorrectly not # recognizing JSON mode. # #test_setup x.fossil | < | | < | > > > > | | | > | > | | > | 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# which writes something (timeline creates a temp table). The "repo
# is not writable" error comes back as HTML. i don't know if the
# error happens before we have made the determination that the app is
# in JSON mode or if the error handling is incorrectly not
# recognizing JSON mode.
#
#test_setup x.fossil
fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Dwal $U1Cookie
test json-ROrepo-1-1 {$CODE == 0}
test json-ROrepo-1-2 {[regexp {\}\s*$} $RESULT]}
test json-ROrepo-1-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}
test_json_envelope_ok json-http-timeline1
if {$is_windows} then {
catch {exec attrib +r .rep.fossil}; # Windows
} else {
catch {exec chmod 444 .rep.fossil}; # Unix
}
protOut "chmod 444 repo"
fossil_http_json /json/query?sql=PRAGMA%20repository.journal_mode%3Ddelete $U1Cookie -expectError --json-preserve-rc
test json-ROrepo-2-1 {$CODE != 0}
test json-ROrepo-2-2 {[regexp {\}\s*$} $RESULT]}
test json-ROrepo-2-3 {![regexp {SQLITE_[A-Z]+:} $RESULT]}
#test_json_envelope_ok json-http-timeline2
if {$is_windows} then {
catch {exec attrib -r .rep.fossil}; # Windows
} else {
catch {exec chmod 666 .rep.fossil}; # Unix
}
protOut "chmod 666 repo"
#### Result Codes
# Test cases designed to stimulate each (documented) error code.
# FOSSIL-0000
# Not returned by any command. We generally verify that in the
# test_json_envelope_ok command by verifying that the resultCode
|
| ︙ | ︙ |
Changes to test/tester.tcl.
| ︙ | ︙ | |||
168 169 170 171 172 173 174 175 176 177 178 179 180 |
}
set keepNewline 0
set index [lsearch -exact $args -keepNewline]
if {$index != -1} {
set keepNewline 1
set args [lreplace $args $index $index]
}
foreach a $args {
lappend cmd $a
}
protOut $cmd
flush stdout
| > > > > > > > > > > | | | | > | | < | < | | > | | < | > > > > > > > > | | | | > | 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
}
set keepNewline 0
set index [lsearch -exact $args -keepNewline]
if {$index != -1} {
set keepNewline 1
set args [lreplace $args $index $index]
}
set whatIf 0
set index [lsearch -exact $args -whatIf]
if {$index != -1} {
set whatIf 1
set args [lreplace $args $index $index]
}
foreach a $args {
lappend cmd $a
}
protOut $cmd
flush stdout
if {$whatIf} {
protOut [pwd]; protOut $answer
set result WHAT-IF-MODE; set rc 42
} else {
if {[string length $answer] > 0} {
protOut $answer
set prompt_file [file join $::tempPath fossil_prompt_answer]
write_file $prompt_file $answer\n
set execCmd [list eval exec]
if {$keepNewline} {lappend execCmd -keepnewline}
lappend execCmd $cmd <$prompt_file
set rc [catch $execCmd result]
file delete $prompt_file
} else {
set execCmd [list eval exec]
if {$keepNewline} {lappend execCmd -keepnewline}
lappend execCmd $cmd
set rc [catch $execCmd result]
}
}
set ab(str) {child process exited abnormally}
set ab(len) [string length $ab(str)]
set ab(off) [expr {$ab(len) - 1}]
if {$rc && $expectError && \
[string range $result end-$ab(off) end] eq $ab(str)} {
set result [string range $result 0 end-$ab(len)]
}
global RESULT CODE
set CODE $rc
if {!$whatIf} {
if {($rc && !$expectError) || (!$rc && $expectError)} {
protOut "ERROR ($rc): $result" 1
} elseif {$::VERBOSE} {
protOut "RESULT ($rc): $result"
}
}
set RESULT $result
}
# Read a file into memory.
#
proc read_file {filename} {
|
| ︙ | ︙ |