Fossil

Check-in [131ba0fa]
Login

Check-in [131ba0fa]

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

Overview
Comment:Attempt to provide more useful error messages when an intermediate server (such as Apache) does something wrong and messes up an HTTP request.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | content-length-errors
Files: files | file ages | folders
SHA3-256: 131ba0fa1bf1e200b3b211c5761041b7dc037d5c41da9fbd289b685db9e00d3e
User & Date: drh 2024-04-16 22:55:16
Context
2024-04-17
12:18
Arrange for the HTTP reply parser to be able to deal with a missing Content-Length header. Add the --xverbose option to the "fossil clone" command. ... (check-in: dfefd069 user: drh tags: content-length-errors)
2024-04-16
22:55
Attempt to provide more useful error messages when an intermediate server (such as Apache) does something wrong and messes up an HTTP request. ... (check-in: 131ba0fa user: drh tags: content-length-errors)
13:50
Improvements to the /test_env page that can be used to help diagnose problems such as missing CONTENT_LENGTH CGI parameters. ... (check-in: 9c40ddbc user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/cgi.c.

1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
      return;
    }
  }
  fputs(z, pLog);
}

/* Forward declaration */
static NORETURN void malformed_request(const char *zMsg);

/*
** Checks the QUERY_STRING environment variable, sets it up
** via add_param_list() and, if found, applies its "skin"
** setting. Returns 0 if no QUERY_STRING is set, 1 if it is,
** and 2 if it sets the skin (in which case the cookie may
** still need flushing by the page, via cookie_render()).







|







1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
      return;
    }
  }
  fputs(z, pLog);
}

/* Forward declaration */
static NORETURN void malformed_request(const char *zMsg, ...);

/*
** Checks the QUERY_STRING environment variable, sets it up
** via add_param_list() and, if found, applies its "skin"
** setting. Returns 0 if no QUERY_STRING is set, 1 if it is,
** and 2 if it sets the skin (in which case the cookie may
** still need flushing by the page, via cookie_render()).
1319
1320
1321
1322
1323
1324
1325

1326
1327
1328
1329
1330
1331
1332
  char *z;
  const char *zType;
  char *zSemi;
  int len;
  const char *zRequestUri = cgi_parameter("REQUEST_URI",0);
  const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
  const char *zPathInfo = cgi_parameter("PATH_INFO",0);

#ifdef _WIN32
  const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
#endif

#ifdef FOSSIL_ENABLE_JSON
  const int noJson = P("no_json")!=0;
#endif







>







1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
  char *z;
  const char *zType;
  char *zSemi;
  int len;
  const char *zRequestUri = cgi_parameter("REQUEST_URI",0);
  const char *zScriptName = cgi_parameter("SCRIPT_NAME",0);
  const char *zPathInfo = cgi_parameter("PATH_INFO",0);
  const char *zContentLength = 0;
#ifdef _WIN32
  const char *zServerSoftware = cgi_parameter("SERVER_SOFTWARE",0);
#endif

#ifdef FOSSIL_ENABLE_JSON
  const int noJson = P("no_json")!=0;
#endif
1416
1417
1418
1419
1420
1421
1422
1423








1424
1425
1426
1427
1428
1429
1430
  cgi_setup_query_string();

  z = (char*)P("REMOTE_ADDR");
  if( z ){
    g.zIpAddr = fossil_strdup(z);
  }

  len = atoi(PD("CONTENT_LENGTH", "0"));








  zType = P("CONTENT_TYPE");
  zSemi = zType ? strchr(zType, ';') : 0;
  if( zSemi ){
    g.zContentType = fossil_strndup(zType, (int)(zSemi-zType));
    zType = g.zContentType;
  }else{
    g.zContentType = zType;







|
>
>
>
>
>
>
>
>







1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
  cgi_setup_query_string();

  z = (char*)P("REMOTE_ADDR");
  if( z ){
    g.zIpAddr = fossil_strdup(z);
  }

  zContentLength = P("CONTENT_LENGTH");
  if( zContentLength==0 ){
    len = 0;
    if( sqlite3_stricmp(PD("REQUEST_METHOD",""),"POST")==0 ){
      malformed_request("missing CONTENT_LENGTH on a POST method");
    }
  }else{
    len = atoi(zContentLength);
  }
  zType = P("CONTENT_TYPE");
  zSemi = zType ? strchr(zType, ';') : 0;
  if( zSemi ){
    g.zContentType = fossil_strndup(zType, (int)(zSemi-zType));
    zType = g.zContentType;
  }else{
    g.zContentType = zType;
1910
1911
1912
1913
1914
1915
1916
1917





1918




1919

1920

1921
1922
1923
1924
1925
1926
1927
1928
  vxprintf(pContent,zFormat,ap);
}


/*
** Send a reply indicating that the HTTP request was malformed
*/
static NORETURN void malformed_request(const char *zMsg){





  cgi_set_status(501, "Not Implemented");




  cgi_printf(

    "<html><body><p>Bad Request: %s</p></body></html>\n", zMsg

  );
  cgi_reply();
  fossil_exit(0);
}

/*
** Panic and die while processing a webpage.
*/







|
>
>
>
>
>
|
>
>
>
>
|
>
|
>
|







1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
  vxprintf(pContent,zFormat,ap);
}


/*
** Send a reply indicating that the HTTP request was malformed
*/
static NORETURN void malformed_request(const char *zMsg, ...){
  va_list ap;
  char *z;
  va_start(ap, zMsg);
  z = vmprintf(zMsg, ap);
  va_end(ap);
  cgi_set_status(400, "Bad Request");
  zContentType = "text/plain";
  if( g.zReqType==0 ) g.zReqType = "WWW";
  if( g.zReqType[0]=='C' && PD("SERVER_SOFTWARE",0)!=0 ){
    const char *zServer = PD("SERVER_SOFTWARE","");
    cgi_printf("Bad CGI Request from \"%s\": %s\n",zServer,z);
  }else{
    cgi_printf("Bad %s Request: %s\n", g.zReqType, z);
  }
  fossil_free(z);
  cgi_reply();
  fossil_exit(0);
}

/*
** Panic and die while processing a webpage.
*/
2031
2032
2033
2034
2035
2036
2037

2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051

2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
*/
void cgi_handle_http_request(const char *zIpAddr){
  char *z, *zToken;
  int i;
  const char *zScheme = "http";
  char zLine[2000];     /* A single line of input. */
  g.fullHttpReply = 1;

  if( cgi_fgets(zLine, sizeof(zLine))==0 ){
    malformed_request("missing HTTP header");
  }
  blob_append(&g.httpHeader, zLine, -1);
  cgi_trace(zLine);
  zToken = extract_token(zLine, &z);
  if( zToken==0 ){
    malformed_request("malformed HTTP header");
  }
  if( fossil_strcmp(zToken,"GET")!=0
   && fossil_strcmp(zToken,"POST")!=0
   && fossil_strcmp(zToken,"HEAD")!=0
  ){
    malformed_request("unsupported HTTP method");

  }
  cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
  cgi_setenv("REQUEST_METHOD",zToken);
  zToken = extract_token(z, &z);
  if( zToken==0 ){
    malformed_request("malformed URL in HTTP header");
  }
  cgi_setenv("REQUEST_URI", zToken);
  cgi_setenv("SCRIPT_NAME", "");
  for(i=0; zToken[i] && zToken[i]!='?'; i++){}
  if( zToken[i] ) zToken[i++] = 0;
  cgi_setenv("PATH_INFO", zToken);
  cgi_setenv("QUERY_STRING", &zToken[i]);







>

|











|
>





|







2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
*/
void cgi_handle_http_request(const char *zIpAddr){
  char *z, *zToken;
  int i;
  const char *zScheme = "http";
  char zLine[2000];     /* A single line of input. */
  g.fullHttpReply = 1;
  g.zReqType = "HTTP";
  if( cgi_fgets(zLine, sizeof(zLine))==0 ){
    malformed_request("missing header");
  }
  blob_append(&g.httpHeader, zLine, -1);
  cgi_trace(zLine);
  zToken = extract_token(zLine, &z);
  if( zToken==0 ){
    malformed_request("malformed HTTP header");
  }
  if( fossil_strcmp(zToken,"GET")!=0
   && fossil_strcmp(zToken,"POST")!=0
   && fossil_strcmp(zToken,"HEAD")!=0
  ){
    malformed_request("unsupported HTTP method: \"%s\" - Fossil only supports"
                      "GET, POST, and HEAD", zToken);
  }
  cgi_setenv("GATEWAY_INTERFACE","CGI/1.0");
  cgi_setenv("REQUEST_METHOD",zToken);
  zToken = extract_token(z, &z);
  if( zToken==0 ){
    malformed_request("malformed URI in the HTTP header");
  }
  cgi_setenv("REQUEST_URI", zToken);
  cgi_setenv("SCRIPT_NAME", "");
  for(i=0; zToken[i] && zToken[i]!='?'; i++){}
  if( zToken[i] ) zToken[i++] = 0;
  cgi_setenv("PATH_INFO", zToken);
  cgi_setenv("QUERY_STRING", &zToken[i]);
2162
2163
2164
2165
2166
2167
2168

2169
2170
2171
2172
2173
2174
2175
    if( nCycles==0 ){
      cgi_setenv("REMOTE_ADDR", zIpAddr);
      g.zIpAddr = fossil_strdup(zIpAddr);
    }
  }else{
    fossil_fatal("missing SSH IP address");
  }

  if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
    malformed_request("missing HTTP header");
  }
  cgi_trace(zLine);
  zToken = extract_token(zLine, &z);
  if( zToken==0 ){
    malformed_request("malformed HTTP header");







>







2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
    if( nCycles==0 ){
      cgi_setenv("REMOTE_ADDR", zIpAddr);
      g.zIpAddr = fossil_strdup(zIpAddr);
    }
  }else{
    fossil_fatal("missing SSH IP address");
  }
  g.zReqType = "HTTP";
  if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
    malformed_request("missing HTTP header");
  }
  cgi_trace(zLine);
  zToken = extract_token(zLine, &z);
  if( zToken==0 ){
    malformed_request("malformed HTTP header");

Changes to src/clone.c.

265
266
267
268
269
270
271







272



273
274
275
276
277
278
279
    nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(zRepo);







      fossil_fatal("server returned an error - clone aborted");



    }
    db_open_repository(zRepo);
  }
  db_begin_transaction();
  if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
    fossil_fatal("there are unresolved deltas -"
                 " the clone is probably incomplete and unusable.");







>
>
>
>
>
>
>
|
>
>
>







265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
    nErr = client_sync(syncFlags,CONFIGSET_ALL,0,0,0);
    g.xlinkClusterOnly = 0;
    verify_cancel();
    db_end_transaction(0);
    db_close(1);
    if( nErr ){
      file_delete(zRepo);
      if( g.fHttpTrace ){
        fossil_fatal(
          "server returned an error - clone aborted\n\n%s",
          http_last_trace_reply()
        );
      }else{
        fossil_fatal(
          "server returned an error - clone aborted\n"
          "Rerun using --httptrace for more detail"
        );
      }
    }
    db_open_repository(zRepo);
  }
  db_begin_transaction();
  if( db_exists("SELECT 1 FROM delta WHERE srcId IN phantom") ){
    fossil_fatal("there are unresolved deltas -"
                 " the clone is probably incomplete and unusable.");

Changes to src/http.c.

45
46
47
48
49
50
51





52
53
54
55
56
57
58

/* Maximum number of HTTP Authorization attempts */
#define MAX_HTTP_AUTH 2

/* Keep track of HTTP Basic Authorization failures */
static int fSeenHttpAuth = 0;






/*
** Construct the "login" card with the client credentials.
**
**       login LOGIN NONCE SIGNATURE
**
** The LOGIN is the user id of the client.  NONCE is the sha1 checksum
** of all payload that follows the login card.  SIGNATURE is the sha1







>
>
>
>
>







45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63

/* Maximum number of HTTP Authorization attempts */
#define MAX_HTTP_AUTH 2

/* Keep track of HTTP Basic Authorization failures */
static int fSeenHttpAuth = 0;

/* The N value for most recent http-request-N.txt and http-reply-N.txt
** trace files.
*/
static int traceCnt = 0;

/*
** Construct the "login" card with the client credentials.
**
**       login LOGIN NONCE SIGNATURE
**
** The LOGIN is the user id of the client.  NONCE is the sha1 checksum
** of all payload that follows the login card.  SIGNATURE is the sha1
387
388
389
390
391
392
393



















394
395
396
397
398
399
400
**      that cache whether or not a PATH= is needed for a particular
**      HOSTNAME.
*/
void ssh_add_path_argument(Blob *pCmd){
  blob_append_escaped_arg(pCmd, 
     "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
}




















/*
** Sign the content in pSend, compress it, and send it to the server
** via HTTP or HTTPS.  Get a reply, uncompress the reply, and store the reply
** in pRecv.  pRecv is assumed to be uninitialized when
** this routine is called - this routine will initialize it.
**







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







392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
**      that cache whether or not a PATH= is needed for a particular
**      HOSTNAME.
*/
void ssh_add_path_argument(Blob *pCmd){
  blob_append_escaped_arg(pCmd, 
     "PATH=$HOME/bin:/usr/local/bin:/opt/homebrew/bin:$PATH", 1);
}

/*
** Return the complete text of the last HTTP reply as saved in the
** http-reply-N.txt file.  This only works if run using --httptrace.
** Without the --httptrace option, this routine returns a NULL pointer.
** It still might return a NULL pointer if for some reason it cannot
** find and open the last http-reply-N.txt file.
*/
char *http_last_trace_reply(void){
  Blob x;
  int n;
  char *zFilename;
  if( g.fHttpTrace==0 ) return 0;
  zFilename = mprintf("http-reply-%d.txt", traceCnt);
  n = blob_read_from_file(&x, zFilename, ExtFILE);
  fossil_free(zFilename);
  if( n<=0 ) return 0;
  return blob_str(&x);
}

/*
** Sign the content in pSend, compress it, and send it to the server
** via HTTP or HTTPS.  Get a reply, uncompress the reply, and store the reply
** in pRecv.  pRecv is assumed to be uninitialized when
** this routine is called - this routine will initialize it.
**
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  /* When tracing, write the transmitted HTTP message both to standard
  ** output and into a file.  The file can then be used to drive the
  ** server-side like this:
  **
  **      ./fossil test-http <http-request-1.txt
  */
  if( g.fHttpTrace ){
    static int traceCnt = 0;
    char *zOutFile;
    FILE *out;
    traceCnt++;
    zOutFile = mprintf("http-request-%d.txt", traceCnt);
    out = fopen(zOutFile, "wb");
    if( out ){
      fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);







<







487
488
489
490
491
492
493

494
495
496
497
498
499
500
  /* When tracing, write the transmitted HTTP message both to standard
  ** output and into a file.  The file can then be used to drive the
  ** server-side like this:
  **
  **      ./fossil test-http <http-request-1.txt
  */
  if( g.fHttpTrace ){

    char *zOutFile;
    FILE *out;
    traceCnt++;
    zOutFile = mprintf("http-request-%d.txt", traceCnt);
    out = fopen(zOutFile, "wb");
    if( out ){
      fwrite(blob_buffer(&hdr), 1, blob_size(&hdr), out);

Changes to src/main.c.

225
226
227
228
229
230
231

232
233
234
235
236
237
238
  UrlData url;            /* Information about current URL */
  const char *zLogin;     /* Login name.  NULL or "" if not logged in. */
  const char *zCkoutAlias;   /* doc/ uses this branch as an alias for "ckout" */
  const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of
                             ** SSL client identity */
  const char *zCgiFile;      /* Name of the CGI file */

#if USE_SEE
  const char *zPidKey;    /* Saved value of the --usepidkey option.  Only
                           * applicable when using SEE on Windows or Linux. */
#endif
  int useLocalauth;       /* No login required if from 127.0.0.1 */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */







>







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  UrlData url;            /* Information about current URL */
  const char *zLogin;     /* Login name.  NULL or "" if not logged in. */
  const char *zCkoutAlias;   /* doc/ uses this branch as an alias for "ckout" */
  const char *zMainMenuFile; /* --mainmenu FILE from server/ui/cgi */
  const char *zSSLIdentity;  /* Value of --ssl-identity option, filename of
                             ** SSL client identity */
  const char *zCgiFile;      /* Name of the CGI file */
  const char *zReqType;      /* Type of request: "HTTP", "CGI", "SCGI" */
#if USE_SEE
  const char *zPidKey;    /* Saved value of the --usepidkey option.  Only
                           * applicable when using SEE on Windows or Linux. */
#endif
  int useLocalauth;       /* No login required if from 127.0.0.1 */
  int noPswd;             /* Logged in without password (on 127.0.0.1) */
  int userUid;            /* Integer user id */
2361
2362
2363
2364
2365
2366
2367

2368
2369
2370
2371
2372
2373
2374
  Blob config, line, key, value, value2;
  /* Initialize the CGI environment. */
  g.httpOut = stdout;
  g.httpIn = stdin;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;

  fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  /* Find the name of the CGI control file */
  if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
    g.zCgiFile = g.argv[2];
  }else if( g.argc>=2 ){
    g.zCgiFile = g.argv[1];
  }else{







>







2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
  Blob config, line, key, value, value2;
  /* Initialize the CGI environment. */
  g.httpOut = stdout;
  g.httpIn = stdin;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.cgiOutput = 1;
  g.zReqType = "CGI";
  fossil_set_timeout(FOSSIL_DEFAULT_TIMEOUT);
  /* Find the name of the CGI control file */
  if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
    g.zCgiFile = g.argv[2];
  }else if( g.argc>=2 ){
    g.zCgiFile = g.argv[1];
  }else{
2844
2845
2846
2847
2848
2849
2850

2851
2852
2853
2854
2855
2856
2857
  noJail = find_option("nojail",0,0)!=0;
  allowRepoList = find_option("repolist",0,0)!=0;
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
  g.fNoHttpCompress = find_option("nocompress",0,0)!=0;
  g.zExtRoot = find_option("extroot",0,1);
  g.zCkoutAlias = find_option("ckout-alias",0,1);

  zInFile = find_option("in",0,1);
  if( zInFile ){
    backoffice_disable();
    g.httpIn = fossil_fopen(zInFile, "rb");
    if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile);
  }else{
    g.httpIn = stdin;







>







2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
  noJail = find_option("nojail",0,0)!=0;
  allowRepoList = find_option("repolist",0,0)!=0;
  g.useLocalauth = find_option("localauth", 0, 0)!=0;
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
  g.fNoHttpCompress = find_option("nocompress",0,0)!=0;
  g.zExtRoot = find_option("extroot",0,1);
  g.zCkoutAlias = find_option("ckout-alias",0,1);
  g.zReqType = "HTTP";
  zInFile = find_option("in",0,1);
  if( zInFile ){
    backoffice_disable();
    g.httpIn = fossil_fopen(zInFile, "rb");
    if( g.httpIn==0 ) fossil_fatal("cannot open \"%s\" for reading", zInFile);
  }else{
    g.httpIn = stdin;
2867
2868
2869
2870
2871
2872
2873

2874
2875
2876
2877
2878
2879
2880
    g.httpOut = stdout;
#if defined(_WIN32)
   _setmode(_fileno(stdout), _O_BINARY);
#endif
  }
  zIpAddr = find_option("ipaddr",0,1);
  useSCGI = find_option("scgi", 0, 0)!=0;

  zAltBase = find_option("baseurl", 0, 1);
  if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay();
  if( zAltBase ) set_base_url(zAltBase);
  if( find_option("https",0,0)!=0 ){
    zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */
    cgi_replace_parameter("HTTPS","on");
  }







>







2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
    g.httpOut = stdout;
#if defined(_WIN32)
   _setmode(_fileno(stdout), _O_BINARY);
#endif
  }
  zIpAddr = find_option("ipaddr",0,1);
  useSCGI = find_option("scgi", 0, 0)!=0;
  if( useSCGI ) g.zReqType = "SCGI";
  zAltBase = find_option("baseurl", 0, 1);
  if( find_option("nodelay",0,0)!=0 ) backoffice_no_delay();
  if( zAltBase ) set_base_url(zAltBase);
  if( find_option("https",0,0)!=0 ){
    zIpAddr = fossil_getenv("REMOTE_HOST"); /* From stunnel */
    cgi_replace_parameter("HTTPS","on");
  }
2993
2994
2995
2996
2997
2998
2999

3000
3001
3002
3003
3004
3005
3006
  login_set_capabilities(zUserCap, 0);
  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);

  g.cgiOutput = 1;
  g.fNoHttpCompress = 1;
  g.fullHttpReply = 1;
  g.sslNotAvailable = 1;  /* Avoid attempts to redirect */
  zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0);
  if( zIpAddr && zIpAddr[0] ){
    g.fSshClient |= CGI_SSH_CLIENT;







>







2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
  login_set_capabilities(zUserCap, 0);
  g.httpIn = stdin;
  g.httpOut = stdout;
  fossil_binary_mode(g.httpOut);
  fossil_binary_mode(g.httpIn);
  g.zExtRoot = find_option("extroot",0,1);
  find_server_repository(2, 0);
  g.zReqType = "HTTP";
  g.cgiOutput = 1;
  g.fNoHttpCompress = 1;
  g.fullHttpReply = 1;
  g.sslNotAvailable = 1;  /* Avoid attempts to redirect */
  zIpAddr = bTest ? 0 : cgi_ssh_remote_addr(0);
  if( zIpAddr && zIpAddr[0] ){
    g.fSshClient |= CGI_SSH_CLIENT;
3229
3230
3231
3232
3233
3234
3235

3236



3237
3238
3239
3240
3241
3242
3243
    zFossilCmd = find_option("fossilcmd", 0, 1);
  }
  zNotFound = find_option("notfound", 0, 1);
  allowRepoList = find_option("repolist",0,0)!=0;
  if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
  zAltBase = find_option("baseurl", 0, 1);
  fCreate = find_option("create",0,0)!=0;

  if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI;



  if( zAltBase ){
    set_base_url(zAltBase);
  }
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd;
  fNoBrowser = find_option("nobrowser", "B", 0)!=0;
  decode_ssl_options();
  if( find_option("https",0,0)!=0 || g.httpUseSSL ){







>
|
>
>
>







3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
    zFossilCmd = find_option("fossilcmd", 0, 1);
  }
  zNotFound = find_option("notfound", 0, 1);
  allowRepoList = find_option("repolist",0,0)!=0;
  if( find_option("nocompress",0,0)!=0 ) g.fNoHttpCompress = 1;
  zAltBase = find_option("baseurl", 0, 1);
  fCreate = find_option("create",0,0)!=0;
  g.zReqType = "HTTP";
  if( find_option("scgi", 0, 0)!=0 ){
    g.zReqType = "SCGI";
    flags |= HTTP_SERVER_SCGI;
  }
  if( zAltBase ){
    set_base_url(zAltBase);
  }
  g.sslNotAvailable = find_option("nossl", 0, 0)!=0 || isUiCmd;
  fNoBrowser = find_option("nobrowser", "B", 0)!=0;
  decode_ssl_options();
  if( find_option("https",0,0)!=0 || g.httpUseSSL ){