Fossil

Check-in [8145cdbf]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:initial code for reading POST data from a file/stdin in CLI mode.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | json-multitag-test | json
Files: files | file ages | folders
SHA1: 8145cdbf3b167efcf304e4ec924aaf85fdfa072d
User & Date: stephan 2011-10-02 12:31:17
Context
2011-10-02
12:41
json mode now accepts command=string request parameter if path length is 1 (no subcommand was specified). check-in: 225fd3da user: stephan tags: json-multitag-test, json
12:31
initial code for reading POST data from a file/stdin in CLI mode. check-in: 8145cdbf user: stephan tags: json-multitag-test, json
11:43
minor cleanups and doc additions to the json/artifact handling. check-in: 6d066783 user: stephan tags: json-multitag-test, json
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/cgi.c.

723
724
725
726
727
728
729
730
731


732
733
734
735
736
737
738
739
740
741


742
743
744
745
746
747
748
...
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
      }
    }
}

/*
** Reads a JSON object from the first contentLen bytes of zIn.  On
** g.json.post is updated to hold the content. On error a
** FSL_JSON_E_INVALID_REQUEST response is output and fossil_exit(0) is
** called.


*/
static void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
  cson_value * jv = NULL;
  int rc;
  CgiPostReadState state;
  assert( 0 != contentLen );
  state.fh = zIn;
  state.len = contentLen;
  state.pos = 0;
  rc = cson_parse( &jv, cson_data_source_FILE_n, &state, NULL, NULL );


  if(rc){
    goto invalidRequest;
  }else{
    json_gc_add( "POST.JSON", jv, 1 );
    g.json.post.v = jv;
    g.json.post.o = cson_value_get_object( jv );
    if( !g.json.post.o ){ /* we don't support non-Object (Array) requests */
................................................................................
      goto invalidRequest;
    }
  }
  return;
  invalidRequest:
  cgi_set_content_type(json_guess_content_type());
  json_err( FSL_JSON_E_INVALID_REQUEST, NULL, 1 );
  fossil_exit(0);
}


/*
** Initialize the query parameter database.  Information is pulled from
** the QUERY_STRING environment variable (if it exists), from standard
** input if there is POST data, and from HTTP_COOKIE.







|
|
>
>

|



<



|
>
>







 







|







723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738

739
740
741
742
743
744
745
746
747
748
749
750
751
...
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
      }
    }
}

/*
** Reads a JSON object from the first contentLen bytes of zIn.  On
** g.json.post is updated to hold the content. On error a
** FSL_JSON_E_INVALID_REQUEST response is output and fossil_exit() is
** called (in HTTP mode exit code 0 is used).
**
** If contentLen is 0 then the whole file is read.
*/
void cgi_parse_POST_JSON( FILE * zIn, unsigned int contentLen ){
  cson_value * jv = NULL;
  int rc;
  CgiPostReadState state;

  state.fh = zIn;
  state.len = contentLen;
  state.pos = 0;
  rc = cson_parse( &jv,
                   contentLen ? cson_data_source_FILE_n : cson_data_source_FILE,
                   contentLen ? (void *)&state : (void *)zIn, NULL, NULL );
  if(rc){
    goto invalidRequest;
  }else{
    json_gc_add( "POST.JSON", jv, 1 );
    g.json.post.v = jv;
    g.json.post.o = cson_value_get_object( jv );
    if( !g.json.post.o ){ /* we don't support non-Object (Array) requests */
................................................................................
      goto invalidRequest;
    }
  }
  return;
  invalidRequest:
  cgi_set_content_type(json_guess_content_type());
  json_err( FSL_JSON_E_INVALID_REQUEST, NULL, 1 );
  fossil_exit( g.isHTTP ? 0 : 1);
}


/*
** Initialize the query parameter database.  Information is pulled from
** the QUERY_STRING environment variable (if it exists), from standard
** input if there is POST data, and from HTTP_COOKIE.

Changes to src/json.c.

885
886
887
888
889
890
891
892




893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911

912
913
914
915
916
917
918
...
929
930
931
932
933
934
935








936
937
938
939
940




















941
942
943
944
945
946
947
...
967
968
969
970
971
972
973
974




975


976
977
978
979
980
981
982
983
  cson_value * pathSplit = NULL;
  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  g.json.jsonp = PD("jsonp",NULL);




  g.json.isJsonMode = 1;
  g.json.resultCode = 0;
  g.json.cmd.offset = -1;
  if( !g.isHTTP && g.fullHttpReply ){
    /* workaround for server mode, so we see it as CGI mode. */
    g.isHTTP = 1;
  }

  /* FIXME: do some sanity checking on g.json.jsonp and ignore it
     if it is not halfway reasonable.
  */
  cgi_set_content_type(json_guess_content_type())
    /* reminder: must be done after g.json.jsonp is initialized */
    ;

#if defined(NDEBUG)
  /* avoids debug messages on stderr in JSON mode */
  sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0);
#endif


  g.json.cmd.v = cson_value_new_array();
  g.json.cmd.a = cson_value_get_array(g.json.cmd.v);
  json_gc_add( FossilJsonKeys.commandPath, g.json.cmd.v, 1 );
  /*
    The following if/else block translates the PATH_INFO path (in
    CLI/server modes) or g.argv (CLI mode) into an internal list so
................................................................................
    int i;
    char const * arg;
    cson_value * part;
    for(i = 1/*skip argv[0]*/; i < g.argc; ++i ){
      arg = g.argv[i];
      if( !arg || !*arg ){
        continue;








      }
      part = cson_value_new_string(arg,strlen(arg));
      cson_array_append(g.json.cmd.a, part);
    }
  }




















  
  /* g.json.reqPayload exists only to simplify some of our access to
     the request payload. We currently only use this in the context of
     Object payloads, not Arrays, strings, etc.
  */
  g.json.reqPayload.v = cson_object_get( g.json.post.o, FossilJsonKeys.payload );
  if( g.json.reqPayload.v ){
................................................................................
      g.json.jsonp = find_option("jsonp",NULL,1);
    }
  }

  {/* set up JSON output formatting options. */
    unsigned char indent = g.isHTTP ? 0 : 1;
    char const * indentStr = NULL;
    if( g.isHTTP ){




      indent = (unsigned char)json_getenv_int("indent",(int)indent);


    }else{/*CLI mode*/
      indentStr = find_option("indent","I",1);
      if(indentStr){
        int const n = atoi(indentStr);
        indent = (n>0)
          ? (unsigned char)n
          : 0;
      }







|
>
>
>
>








|
<
<
|
|
|
<
<
|
|
<
>







 







>
>
>
>
>
>
>
>





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|
>
>
>
>
|
>
>
|







885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905


906
907
908


909
910

911
912
913
914
915
916
917
918
...
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
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
...
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  cson_value * pathSplit = NULL;
  assert( (0==once) && "json_mode_bootstrap() called too many times!");
  if( once ){
    return;
  }else{
    once = 1;
  }
  g.json.jsonp = PD("jsonp",NULL)
    /* FIXME: do some sanity checking on g.json.jsonp and ignore it
       if it is not halfway reasonable.
    */
    ;
  g.json.isJsonMode = 1;
  g.json.resultCode = 0;
  g.json.cmd.offset = -1;
  if( !g.isHTTP && g.fullHttpReply ){
    /* workaround for server mode, so we see it as CGI mode. */
    g.isHTTP = 1;
  }

  if(g.isHTTP){


    cgi_set_content_type(json_guess_content_type())
      /* reminder: must be done after g.json.jsonp is initialized */
      ;


    /* avoids debug messages on stderr in JSON mode */
    sqlite3_config(SQLITE_CONFIG_LOG, NULL, 0);

  }

  g.json.cmd.v = cson_value_new_array();
  g.json.cmd.a = cson_value_get_array(g.json.cmd.v);
  json_gc_add( FossilJsonKeys.commandPath, g.json.cmd.v, 1 );
  /*
    The following if/else block translates the PATH_INFO path (in
    CLI/server modes) or g.argv (CLI mode) into an internal list so
................................................................................
    int i;
    char const * arg;
    cson_value * part;
    for(i = 1/*skip argv[0]*/; i < g.argc; ++i ){
      arg = g.argv[i];
      if( !arg || !*arg ){
        continue;
      }
      if('-' == *arg){
        /* workaround to skip CLI args so that
           json_command_arg() does not see them.
           This assumes that all arguments come LAST
           on the command line.
        */
        break;
      }
      part = cson_value_new_string(arg,strlen(arg));
      cson_array_append(g.json.cmd.a, part);
    }
  }

  while(!g.isHTTP){ /* simulate JSON POST data via input file. */
    FILE * inFile = NULL;
    char const * jfile = find_option("json-input",NULL,1);
    if(!jfile || !*jfile){
      break;
    }
    inFile = (0==strcmp("-",jfile))
      ? stdin
      : fopen(jfile,"rb");
    if(!inFile){
      json_err(FSL_JSON_E_UNKNOWN,"Could not open JSON file.",1);
      fossil_exit(1);
    }
    cgi_parse_POST_JSON(inFile, 0);
    if( stdin != inFile ){
      fclose(inFile);
    }
    break;
  }
  
  /* g.json.reqPayload exists only to simplify some of our access to
     the request payload. We currently only use this in the context of
     Object payloads, not Arrays, strings, etc.
  */
  g.json.reqPayload.v = cson_object_get( g.json.post.o, FossilJsonKeys.payload );
  if( g.json.reqPayload.v ){
................................................................................
      g.json.jsonp = find_option("jsonp",NULL,1);
    }
  }

  {/* set up JSON output formatting options. */
    unsigned char indent = g.isHTTP ? 0 : 1;
    char const * indentStr = NULL;
    char checkAgain = 1;
    if( g.json.post.v ){
      cson_value const * check = json_getenv("indent");
      if(check){
        checkAgain = 0;
        indent = (unsigned char)json_getenv_int("indent",(int)indent);
      }
    }
    if(!g.isHTTP && checkAgain){/*CLI mode*/
      indentStr = find_option("indent","I",1);
      if(indentStr){
        int const n = atoi(indentStr);
        indent = (n>0)
          ? (unsigned char)n
          : 0;
      }

Changes to src/json_timeline.c.

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
** else it returns some statically defined default value.
**
** Never returns a negative value. 0 means no limit.
*/
static int json_timeline_limit(){
  static const int defaultLimit = 20;
  int limit = -1;
  if( g.isHTTP ){
    limit = json_getenv_int("limit",-1);
    if(limit<0){
      limit = json_getenv_int("n",-1);
    }
  }else{/* CLI mode */
    char const * arg = find_option("limit","n",1);
    if(arg && *arg){
      limit = atoi(arg);
    }
  }
  return (limit<0) ? defaultLimit : limit;
}







|




|







165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
** else it returns some statically defined default value.
**
** Never returns a negative value. 0 means no limit.
*/
static int json_timeline_limit(){
  static const int defaultLimit = 20;
  int limit = -1;
  if( g.json.post.v ){
    limit = json_getenv_int("limit",-1);
    if(limit<0){
      limit = json_getenv_int("n",-1);
    }
  }else if(!g.isHTTP){/* CLI mode */
    char const * arg = find_option("limit","n",1);
    if(arg && *arg){
      limit = atoi(arg);
    }
  }
  return (limit<0) ? defaultLimit : limit;
}