Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | More cleaning up of error lower-level handling to output JSON instead of HTML in a few more cases. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | json |
| Files: | files | file ages | folders |
| SHA1: |
9b842564f746286f4255d79a1ee1d9b6 |
| User & Date: | stephan 2011-09-17 16:01:13.683 |
Context
|
2011-09-17
| ||
| 20:25 | added a missing assert() (Thanks, Joe M.) ... (check-in: a67c6744e5 user: stephan tags: json) | |
| 16:01 | More cleaning up of error lower-level handling to output JSON instead of HTML in a few more cases. ... (check-in: 9b842564f7 user: stephan tags: json) | |
| 14:24 | logout now fails if the auth token is not available to it (as a sanity check and potentially stop someone from logging out someone else). ... (check-in: affdf56c3f user: stephan tags: json) | |
Changes
Changes to src/cgi.c.
| ︙ | ︙ | |||
946 947 948 949 950 951 952 |
/*
** Panic and die while processing a webpage.
*/
void cgi_panic(const char *zFormat, ...){
va_list ap;
cgi_reset_content();
| > > > > > > > > > | | | | | | | | | | > | 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 |
/*
** Panic and die while processing a webpage.
*/
void cgi_panic(const char *zFormat, ...){
va_list ap;
cgi_reset_content();
if( g.json.isJsonMode ){
char * zMsg;
va_start(ap, zFormat);
zMsg = vmprintf(zFormat,ap);
va_end(ap);
json_err( FSL_JSON_E_PANIC, zMsg, 1 );
free(zMsg);
fossil_exit( g.isCGI ? 0 : 1 );
}else{
cgi_set_status(500, "Internal Server Error");
cgi_printf(
"<html><body><h1>Internal Server Error</h1>\n"
"<plaintext>"
);
va_start(ap, zFormat);
vxprintf(pContent,zFormat,ap);
va_end(ap);
cgi_reply();
fossil_exit(1);
}
}
/*
** Remove the first space-delimited token from a string and return
** a pointer to it. Add a NULL to the string to terminate the token.
** Make *zLeftOver point to the start of the next token.
*/
|
| ︙ | ︙ |
Changes to src/json.c.
| ︙ | ︙ | |||
26 27 28 29 30 31 32 | #include "VERSION.h" #include "json.h" #include <assert.h> #include <time.h> #if INTERFACE #include "cson_amalgamation.h" | < < < < < < < < < < < < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include "VERSION.h"
#include "json.h"
#include <assert.h>
#include <time.h>
#if INTERFACE
#include "cson_amalgamation.h"
#include "json_detail.h" /* workaround for apparent enum limitation in makeheaders */
#endif
/*
** Holds keys used for various JSON API properties.
*/
static const struct FossilJsonKeys_{
char const * authToken;
|
| ︙ | ︙ | |||
636 637 638 639 640 641 642 | ** g.json.resultCode is used. If that is also 0 then the "Unknown ** Error" code is used. ** ** If g.isCGI then the generated error object replaces any currently ** buffered page output. ** ** If alsoOutput is true AND g.isCGI then the cgi_reply() is called to | | | | 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 | ** g.json.resultCode is used. If that is also 0 then the "Unknown ** Error" code is used. ** ** If g.isCGI then the generated error object replaces any currently ** buffered page output. ** ** If alsoOutput is true AND g.isCGI then the cgi_reply() is called to ** flush the output (and headers). Generally only do this if you are ** about to call exit(). ** ** !g.isCGI then alsoOutput is ignored and all output is sent to ** stdout immediately. ** ** This clears any previously buffered CGI content, replacing it with ** JSON. */ |
| ︙ | ︙ | |||
688 689 690 691 692 693 694 695 696 697 698 699 700 701 |
FSET(MANIFEST_VERSION,"manifestVersion");
FSET(MANIFEST_DATE,"manifestDate");
FSET(MANIFEST_YEAR,"manifestYear");
FSET(RELEASE_VERSION,"releaseVersion");
#undef FSET
cson_object_set( jobj, "releaseVersionNumber",
cson_value_new_integer(RELEASE_VERSION_NUMBER) );
return jval;
}
#if 0
/* we have a disconnect here between fossil's server-mode QUERY_STRING
handling and cson_cgi's.
*/
| > > | 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
FSET(MANIFEST_VERSION,"manifestVersion");
FSET(MANIFEST_DATE,"manifestDate");
FSET(MANIFEST_YEAR,"manifestYear");
FSET(RELEASE_VERSION,"releaseVersion");
#undef FSET
cson_object_set( jobj, "releaseVersionNumber",
cson_value_new_integer(RELEASE_VERSION_NUMBER) );
cson_object_set( jobj, "resultCodeParanoiaLevel",
cson_value_new_integer(g.json.errorDetailParanoia) );
return jval;
}
#if 0
/* we have a disconnect here between fossil's server-mode QUERY_STRING
handling and cson_cgi's.
*/
|
| ︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 |
** timeline
** tickets
** ...
**
*/
void json_cmd_top(void){
char const * cmd = NULL;
| < < | | 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 |
** timeline
** tickets
** ...
**
*/
void json_cmd_top(void){
char const * cmd = NULL;
int rc = 1002;
cson_value * payload = NULL;
JsonPageDef const * pageDef;
json_mode_bootstrap();
if( g.argc<3 ){
goto usage;
}
db_find_and_open_repository(0, 0);
cmd = json_command_arg(1);
if( !cmd || !*cmd ){
goto usage;
}
cgi_set_content_type( cson_cgi_guess_content_type(&g.json.cgiCx) );
pageDef = json_handler_for_name(cmd,&JsonPageDefs[0]);
if( ! pageDef ){
json_err( FSL_JSON_E_UNKNOWN_COMMAND, NULL, 1 );
return;
|
| ︙ | ︙ | |||
1114 1115 1116 1117 1118 1119 1120 |
cson_output_FILE( payload, stdout, &g.json.outOpt );
cson_value_free( payload );
if((0 != rc) && !g.isCGI){
/* FIXME: we need a way of passing this error back
up to the routine which called this callback.
e.g. add g.errCode.
*/
| | | 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 |
cson_output_FILE( payload, stdout, &g.json.outOpt );
cson_value_free( payload );
if((0 != rc) && !g.isCGI){
/* FIXME: we need a way of passing this error back
up to the routine which called this callback.
e.g. add g.errCode.
*/
fossil_exit(1);
}
}
return;
usage:
usage("subcommand");
}
|
Added src/json_detail.h.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
/*
** Impl details for the JSON API which need to be shared
** across multiple C files.
*/
/*
** The "official" list of Fossil/JSON error codes.
** Their values might very well change during initial
** development but after their first public release
** they must stay stable.
** Values must be in the range 1..9999
**
** Numbers evenly dividable by 100 are "categories",
** and error codes for a given category have their
** high bits set to the category value.
**
*/
enum FossilJsonCodes {
FSL_JSON_E_GENERIC = 1000,
FSL_JSON_E_GENERIC_SUB1 = FSL_JSON_E_GENERIC + 100,
FSL_JSON_E_INVALID_REQUEST = FSL_JSON_E_GENERIC_SUB1 + 1,
FSL_JSON_E_UNKNOWN_COMMAND = FSL_JSON_E_GENERIC_SUB1 + 2,
FSL_JSON_E_UNKNOWN = FSL_JSON_E_GENERIC_SUB1 + 3,
FSL_JSON_E_RESOURCE_NOT_FOUND = FSL_JSON_E_GENERIC_SUB1 + 4,
FSL_JSON_E_TIMEOUT = FSL_JSON_E_GENERIC_SUB1 + 5,
FSL_JSON_E_ASSERT = FSL_JSON_E_GENERIC_SUB1 + 6,
FSL_JSON_E_ALLOC = FSL_JSON_E_GENERIC_SUB1 + 7,
FSL_JSON_E_NYI = FSL_JSON_E_GENERIC_SUB1 + 8,
FSL_JSON_E_PANIC = FSL_JSON_E_GENERIC_SUB1 + 9,
FSL_JSON_E_AUTH = 2000,
FSL_JSON_E_MISSING_AUTH = FSL_JSON_E_AUTH + 1,
FSL_JSON_E_DENIED = FSL_JSON_E_AUTH + 2,
FSL_JSON_E_WRONG_MODE = FSL_JSON_E_AUTH + 3,
FSL_JSON_E_LOGIN_FAILED = FSL_JSON_E_AUTH + 100,
FSL_JSON_E_LOGIN_FAILED_NONAME = FSL_JSON_E_LOGIN_FAILED + 1,
FSL_JSON_E_LOGIN_FAILED_NOPW = FSL_JSON_E_LOGIN_FAILED + 2,
FSL_JSON_E_LOGIN_FAILED_NOTFOUND = FSL_JSON_E_LOGIN_FAILED + 3,
FSL_JSON_E_USAGE = 3000,
FSL_JSON_E_INVALID_ARGS = FSL_JSON_E_USAGE + 1,
FSL_JSON_E_MISSING_ARGS = FSL_JSON_E_USAGE + 2,
FSL_JSON_E_DB = 4000,
FSL_JSON_E_STMT_PREP = FSL_JSON_E_DB + 1,
FSL_JSON_E_STMT_BIND = FSL_JSON_E_DB + 2,
FSL_JSON_E_STMT_EXEC = FSL_JSON_E_DB + 3,
FSL_JSON_E_DB_LOCKED = FSL_JSON_E_DB + 4,
FSL_JSON_E_DB_NEEDS_REBUILD = FSL_JSON_E_DB + 101
};
|
Changes to src/main.c.
| ︙ | ︙ | |||
24 25 26 27 28 29 30 | #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> /* atexit() */ #if INTERFACE | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <time.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <stdlib.h> /* atexit() */ #if INTERFACE #include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */ /* ** Number of elements in an array */ #define count(X) (sizeof(X)/sizeof(X[0])) /* |
| ︙ | ︙ | |||
1032 1033 1034 1035 1036 1037 1038 |
zRepo[j] = '.';
}
if( szFile<1024 ){
if( zNotFound ){
cgi_redirect(zNotFound);
}else{
| > > > | | | > | 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 |
zRepo[j] = '.';
}
if( szFile<1024 ){
if( zNotFound ){
cgi_redirect(zNotFound);
}else{
if(g.json.isJsonMode){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
}else{
@ <h1>Not Found</h1>
cgi_set_status(404, "not found");
cgi_reply();
}
}
return;
}
break;
}
zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
|
| ︙ | ︙ | |||
1063 1064 1065 1066 1067 1068 1069 |
*/
if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
zPathInfo = "/xfer";
}
set_base_url();
if( zPathInfo==0 || zPathInfo[0]==0
|| (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
| > > > > | > | 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
*/
if( g.zContentType && memcmp(g.zContentType, "application/x-fossil", 20)==0 ){
zPathInfo = "/xfer";
}
set_base_url();
if( zPathInfo==0 || zPathInfo[0]==0
|| (zPathInfo[0]=='/' && zPathInfo[1]==0) ){
if(g.json.isJsonMode){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1);
fossil_exit(0);
}else{
fossil_redirect_home() /*does not return*/;
}
}else{
zPath = mprintf("%s", zPathInfo);
}
/* Make g.zPath point to the first element of the path. Make
** g.zExtra point to everything past that point.
*/
|
| ︙ | ︙ | |||
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 |
g.zExtra = 0;
}
break;
}
if( g.zExtra ){
/* CGI parameters get this treatment elsewhere, but places like getfile
** will use g.zExtra directly.
*/
dehttpize(g.zExtra);
cgi_set_parameter_nocopy("name", g.zExtra);
}
/* Locate the method specified by the path and execute the function
** that implements that method.
*/
if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) &&
name_search("not_found", aWebpage, count(aWebpage), &idx) ){
| > > > > > | | | > > > > | | | > | 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 |
g.zExtra = 0;
}
break;
}
if( g.zExtra ){
/* CGI parameters get this treatment elsewhere, but places like getfile
** will use g.zExtra directly.
** Reminder: the login mechanism uses 'name' differently, and may
** eventually have a problem/collision with this.
*/
dehttpize(g.zExtra);
cgi_set_parameter_nocopy("name", g.zExtra);
}
/* Locate the method specified by the path and execute the function
** that implements that method.
*/
if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) &&
name_search("not_found", aWebpage, count(aWebpage), &idx) ){
if(g.json.isJsonMode){
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
}else{
cgi_set_status(404,"Not Found");
@ <h1>Not Found</h1>
@ <p>Page not found: %h(g.zPath)</p>
}
}else if( aWebpage[idx].xFunc!=page_xfer && db_schema_is_outofdate() ){
if(g.json.isJsonMode){
json_err(FSL_JSON_E_DB_NEEDS_REBUILD,NULL,0);
}else{
@ <h1>Server Configuration Error</h1>
@ <p>The database schema on the server is out-of-date. Please ask
@ the administrator to run <b>fossil rebuild</b>.</p>
}
}else{
aWebpage[idx].xFunc();
}
/* Return the result.
*/
cgi_reply();
|
| ︙ | ︙ |