Fossil SCM
For commands "ui", "server", and "http", and for CGI, when a directory is supplied instead of a specific repository, add the ability to show a list of available repositories under that directory. Enabled by default with the "ui" command. Use --repolist with "server" and "http" and the "repolist" attribute in the CGI script to enable.
Commit
87508e0bf995f4eaee57cdba22fa2875b7bfece4
Parent
3216a9cb2aeb513…
1 file changed
+77
-23
+77
-23
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -1408,10 +1408,48 @@ | ||
| 1408 | 1408 | } |
| 1409 | 1409 | } |
| 1410 | 1410 | #endif |
| 1411 | 1411 | return zRepo; |
| 1412 | 1412 | } |
| 1413 | + | |
| 1414 | +/* | |
| 1415 | +** Generate a web-page that lists all repositories located under the | |
| 1416 | +** g.zRepositoryName directory and return non-zero. | |
| 1417 | +** | |
| 1418 | +** Or, if no repositories can be located beneath g.zRepositoryName, | |
| 1419 | +** return 0. | |
| 1420 | +*/ | |
| 1421 | +static int repo_list_page(void){ | |
| 1422 | + Blob base; | |
| 1423 | + int n = 0; | |
| 1424 | + | |
| 1425 | + assert( g.db==0 ); | |
| 1426 | + blob_init(&base, g.zRepositoryName, -1); | |
| 1427 | + sqlite3_open(":memory:", &g.db); | |
| 1428 | + db_multi_exec("CREATE TABLE sfile(x TEXT);"); | |
| 1429 | + db_multi_exec("CREATE TABLE vfile(pathname);"); | |
| 1430 | + vfile_scan(&base, blob_size(&base), 0, 0, 0); | |
| 1431 | + db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*.fossil'"); | |
| 1432 | + n = db_int(0, "SELECT count(*) FROM sfile"); | |
| 1433 | + if( n>0 ){ | |
| 1434 | + Stmt q; | |
| 1435 | + @ <h1>Available Repositories:</h1> | |
| 1436 | + @ <ol> | |
| 1437 | + db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'" | |
| 1438 | + " FROM sfile ORDER BY x COLLATE nocase;"); | |
| 1439 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1440 | + const char *zName = db_column_text(&q, 0); | |
| 1441 | + const char *zUrl = db_column_text(&q, 1); | |
| 1442 | + @ <li><a href="%h(zUrl)">%h(zName)</a></li> | |
| 1443 | + } | |
| 1444 | + @ </ol> | |
| 1445 | + cgi_reply(); | |
| 1446 | + } | |
| 1447 | + sqlite3_close(g.db); | |
| 1448 | + g.db = 0; | |
| 1449 | + return n; | |
| 1450 | +} | |
| 1413 | 1451 | |
| 1414 | 1452 | /* |
| 1415 | 1453 | ** Preconditions: |
| 1416 | 1454 | ** |
| 1417 | 1455 | ** * Environment variables are set up according to the CGI standard. |
| @@ -1431,11 +1469,15 @@ | ||
| 1431 | 1469 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1432 | 1470 | ** returned as static text. |
| 1433 | 1471 | ** |
| 1434 | 1472 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1435 | 1473 | */ |
| 1436 | -static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ | |
| 1474 | +static void process_one_web_page( | |
| 1475 | + const char *zNotFound, /* Redirect here on a 404 if not NULL */ | |
| 1476 | + Glob *pFileGlob, /* Deliver static files matching */ | |
| 1477 | + int allowRepoList /* Send repo list for "/" URL */ | |
| 1478 | +){ | |
| 1437 | 1479 | const char *zPathInfo; |
| 1438 | 1480 | char *zPath = NULL; |
| 1439 | 1481 | int idx; |
| 1440 | 1482 | int i; |
| 1441 | 1483 | |
| @@ -1506,10 +1548,12 @@ | ||
| 1506 | 1548 | |
| 1507 | 1549 | if( szFile<1024 ){ |
| 1508 | 1550 | set_base_url(0); |
| 1509 | 1551 | if( zNotFound ){ |
| 1510 | 1552 | cgi_redirect(zNotFound); |
| 1553 | + }else if( strcmp(zPathInfo,"/")==0 && repo_list_page() ){ | |
| 1554 | + /* Will return a list of repositories */ | |
| 1511 | 1555 | }else{ |
| 1512 | 1556 | #ifdef FOSSIL_ENABLE_JSON |
| 1513 | 1557 | if(g.json.isJsonMode){ |
| 1514 | 1558 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1515 | 1559 | return; |
| @@ -1805,10 +1849,11 @@ | ||
| 1805 | 1849 | const char *zFile; |
| 1806 | 1850 | const char *zNotFound = 0; |
| 1807 | 1851 | char **azRedirect = 0; /* List of repositories to redirect to */ |
| 1808 | 1852 | int nRedirect = 0; /* Number of entries in azRedirect */ |
| 1809 | 1853 | Glob *pFileGlob = 0; /* Pattern for files */ |
| 1854 | + int allowRepoList = 0; /* Allow lists of repository files */ | |
| 1810 | 1855 | Blob config, line, key, value, value2; |
| 1811 | 1856 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 1812 | 1857 | zFile = g.argv[2]; |
| 1813 | 1858 | }else{ |
| 1814 | 1859 | zFile = g.argv[1]; |
| @@ -1862,10 +1907,19 @@ | ||
| 1862 | 1907 | ** Grant "administrator" privileges to users connecting with HTTP |
| 1863 | 1908 | ** from IP address 127.0.0.1. Do not bother checking credentials. |
| 1864 | 1909 | */ |
| 1865 | 1910 | g.useLocalauth = 1; |
| 1866 | 1911 | continue; |
| 1912 | + } | |
| 1913 | + if( blob_eq(&key, "repolist") ){ | |
| 1914 | + /* repolist | |
| 1915 | + ** | |
| 1916 | + ** If using "directory:" and the URL is "/" then generate a page | |
| 1917 | + ** showing a list of available repositories. | |
| 1918 | + */ | |
| 1919 | + allowRepoList = 1; | |
| 1920 | + continue; | |
| 1867 | 1921 | } |
| 1868 | 1922 | if( blob_eq(&key, "redirect:") && blob_token(&line, &value) |
| 1869 | 1923 | && blob_token(&line, &value2) ){ |
| 1870 | 1924 | /* See the header comment on the redirect_web_page() function |
| 1871 | 1925 | ** above for details. */ |
| @@ -1952,11 +2006,11 @@ | ||
| 1952 | 2006 | } |
| 1953 | 2007 | cgi_init(); |
| 1954 | 2008 | if( nRedirect ){ |
| 1955 | 2009 | redirect_web_page(nRedirect, azRedirect); |
| 1956 | 2010 | }else{ |
| 1957 | - process_one_web_page(zNotFound, pFileGlob); | |
| 2011 | + process_one_web_page(zNotFound, pFileGlob, allowRepoList); | |
| 1958 | 2012 | } |
| 1959 | 2013 | } |
| 1960 | 2014 | |
| 1961 | 2015 | /* |
| 1962 | 2016 | ** If g.argv[arg] exists then it is either the name of a repository |
| @@ -1970,24 +2024,17 @@ | ||
| 1970 | 2024 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 1971 | 2025 | ** a directory full of repositories, then set g.zRepositoryName to |
| 1972 | 2026 | ** the name of that directory and the specific repository will be |
| 1973 | 2027 | ** opened later by process_one_web_page() based on the content of |
| 1974 | 2028 | ** the PATH_INFO variable. |
| 1975 | -** | |
| 1976 | -** If disallowDir is set, then the directory full of repositories method | |
| 1977 | -** is disallowed. | |
| 1978 | 2029 | */ |
| 1979 | -static void find_server_repository(int disallowDir, int arg){ | |
| 2030 | +static void find_server_repository(int arg){ | |
| 1980 | 2031 | if( g.argc<=arg ){ |
| 1981 | 2032 | db_must_be_within_tree(); |
| 1982 | 2033 | }else if( file_isdir(g.argv[arg])==1 ){ |
| 1983 | - if( disallowDir ){ | |
| 1984 | - fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[arg]); | |
| 1985 | - }else{ | |
| 1986 | - g.zRepositoryName = mprintf("%s", g.argv[arg]); | |
| 1987 | - file_simplify_name(g.zRepositoryName, -1, 0); | |
| 1988 | - } | |
| 2034 | + g.zRepositoryName = mprintf("%s", g.argv[arg]); | |
| 2035 | + file_simplify_name(g.zRepositoryName, -1, 0); | |
| 1989 | 2036 | }else{ |
| 1990 | 2037 | db_open_repository(g.argv[arg]); |
| 1991 | 2038 | } |
| 1992 | 2039 | } |
| 1993 | 2040 | |
| @@ -2028,18 +2075,19 @@ | ||
| 2028 | 2075 | ** If the --localauth option is given, then automatic login is performed |
| 2029 | 2076 | ** for requests coming from localhost, if the "localauth" setting is not |
| 2030 | 2077 | ** enabled. |
| 2031 | 2078 | ** |
| 2032 | 2079 | ** Options: |
| 2080 | +** --baseurl URL base URL (useful with reverse proxies) | |
| 2081 | +** --files GLOB comma-separate glob patterns for static file to serve | |
| 2033 | 2082 | ** --localauth enable automatic login for local connections |
| 2034 | 2083 | ** --host NAME specify hostname of the server |
| 2035 | 2084 | ** --https signal a request coming in via https |
| 2036 | 2085 | ** --nojail drop root privilege but do not enter the chroot jail |
| 2037 | 2086 | ** --nossl signal that no SSL connections are available |
| 2038 | 2087 | ** --notfound URL use URL as "HTTP 404, object not found" page. |
| 2039 | -** --files GLOB comma-separate glob patterns for static file to serve | |
| 2040 | -** --baseurl URL base URL (useful with reverse proxies) | |
| 2088 | +** --repolist If REPOSITORY is directory, URL "/" lists all repos | |
| 2041 | 2089 | ** --scgi Interpret input as SCGI rather than HTTP |
| 2042 | 2090 | ** --skin LABEL Use override skin LABEL |
| 2043 | 2091 | ** |
| 2044 | 2092 | ** See also: cgi, server, winsrv |
| 2045 | 2093 | */ |
| @@ -2049,10 +2097,11 @@ | ||
| 2049 | 2097 | const char *zHost; |
| 2050 | 2098 | const char *zAltBase; |
| 2051 | 2099 | const char *zFileGlob; |
| 2052 | 2100 | int useSCGI; |
| 2053 | 2101 | int noJail; |
| 2102 | + int allowRepoList; | |
| 2054 | 2103 | |
| 2055 | 2104 | /* The winhttp module passes the --files option as --files-urlenc with |
| 2056 | 2105 | ** the argument being URL encoded, to avoid wildcard expansion in the |
| 2057 | 2106 | ** shell. This option is for internal use and is undocumented. |
| 2058 | 2107 | */ |
| @@ -2065,10 +2114,11 @@ | ||
| 2065 | 2114 | zFileGlob = find_option("files",0,1); |
| 2066 | 2115 | } |
| 2067 | 2116 | skin_override(); |
| 2068 | 2117 | zNotFound = find_option("notfound", 0, 1); |
| 2069 | 2118 | noJail = find_option("nojail",0,0)!=0; |
| 2119 | + allowRepoList = find_option("repolist",0,0)!=0; | |
| 2070 | 2120 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2071 | 2121 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2072 | 2122 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2073 | 2123 | zAltBase = find_option("baseurl", 0, 1); |
| 2074 | 2124 | if( zAltBase ) set_base_url(zAltBase); |
| @@ -2089,15 +2139,15 @@ | ||
| 2089 | 2139 | g.fullHttpReply = 1; |
| 2090 | 2140 | if( g.argc>=5 ){ |
| 2091 | 2141 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2092 | 2142 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2093 | 2143 | zIpAddr = g.argv[4]; |
| 2094 | - find_server_repository(0, 5); | |
| 2144 | + find_server_repository(5); | |
| 2095 | 2145 | }else{ |
| 2096 | 2146 | g.httpIn = stdin; |
| 2097 | 2147 | g.httpOut = stdout; |
| 2098 | - find_server_repository(0, 2); | |
| 2148 | + find_server_repository(2); | |
| 2099 | 2149 | } |
| 2100 | 2150 | if( zIpAddr==0 ){ |
| 2101 | 2151 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2102 | 2152 | if( zIpAddr && zIpAddr[0] ){ |
| 2103 | 2153 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2109,21 +2159,21 @@ | ||
| 2109 | 2159 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2110 | 2160 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2111 | 2161 | }else{ |
| 2112 | 2162 | cgi_handle_http_request(zIpAddr); |
| 2113 | 2163 | } |
| 2114 | - process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 2164 | + process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); | |
| 2115 | 2165 | } |
| 2116 | 2166 | |
| 2117 | 2167 | /* |
| 2118 | 2168 | ** Process all requests in a single SSH connection if possible. |
| 2119 | 2169 | */ |
| 2120 | 2170 | void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ |
| 2121 | 2171 | blob_zero(&g.cgiIn); |
| 2122 | 2172 | do{ |
| 2123 | 2173 | cgi_handle_ssh_http_request(zIpAddr); |
| 2124 | - process_one_web_page(0, FileGlob); | |
| 2174 | + process_one_web_page(0, FileGlob, 0); | |
| 2125 | 2175 | blob_reset(&g.cgiIn); |
| 2126 | 2176 | } while ( g.fSshClient & CGI_SSH_FOSSIL || |
| 2127 | 2177 | g.fSshClient & CGI_SSH_COMPAT ); |
| 2128 | 2178 | } |
| 2129 | 2179 | |
| @@ -2140,21 +2190,21 @@ | ||
| 2140 | 2190 | Th_InitTraceLog(); |
| 2141 | 2191 | login_set_capabilities("sx", 0); |
| 2142 | 2192 | g.useLocalauth = 1; |
| 2143 | 2193 | g.httpIn = stdin; |
| 2144 | 2194 | g.httpOut = stdout; |
| 2145 | - find_server_repository(0, 2); | |
| 2195 | + find_server_repository(2); | |
| 2146 | 2196 | g.cgiOutput = 1; |
| 2147 | 2197 | g.fullHttpReply = 1; |
| 2148 | 2198 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2149 | 2199 | if( zIpAddr && zIpAddr[0] ){ |
| 2150 | 2200 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2151 | 2201 | ssh_request_loop(zIpAddr, 0); |
| 2152 | 2202 | }else{ |
| 2153 | 2203 | cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); |
| 2154 | 2204 | cgi_handle_http_request(0); |
| 2155 | - process_one_web_page(0, 0); | |
| 2205 | + process_one_web_page(0, 0, 0); | |
| 2156 | 2206 | } |
| 2157 | 2207 | } |
| 2158 | 2208 | |
| 2159 | 2209 | #if !defined(_WIN32) |
| 2160 | 2210 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| @@ -2227,10 +2277,11 @@ | ||
| 2227 | 2277 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2228 | 2278 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2229 | 2279 | ** --notfound URL Redirect |
| 2230 | 2280 | ** -P|--port TCPPORT listen to request on port TCPPORT |
| 2231 | 2281 | ** --th-trace trace TH1 execution (for debugging purposes) |
| 2282 | +** --repolist If REPOSITORY is dir, URL "/" lists repos. | |
| 2232 | 2283 | ** --scgi Accept SCGI rather than HTTP |
| 2233 | 2284 | ** --skin LABEL Use override skin LABEL |
| 2234 | 2285 | |
| 2235 | 2286 | ** |
| 2236 | 2287 | ** See also: cgi, http, winsrv |
| @@ -2244,10 +2295,11 @@ | ||
| 2244 | 2295 | const char *zNotFound; /* The --notfound option or NULL */ |
| 2245 | 2296 | int flags = 0; /* Server flags */ |
| 2246 | 2297 | #if !defined(_WIN32) |
| 2247 | 2298 | int noJail; /* Do not enter the chroot jail */ |
| 2248 | 2299 | #endif |
| 2300 | + int allowRepoList; /* List repositories on URL "/" */ | |
| 2249 | 2301 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2250 | 2302 | const char *zFileGlob; /* Static content must match this */ |
| 2251 | 2303 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2252 | 2304 | |
| 2253 | 2305 | #if defined(_WIN32) |
| @@ -2269,10 +2321,11 @@ | ||
| 2269 | 2321 | #endif |
| 2270 | 2322 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2271 | 2323 | Th_InitTraceLog(); |
| 2272 | 2324 | zPort = find_option("port", "P", 1); |
| 2273 | 2325 | zNotFound = find_option("notfound", 0, 1); |
| 2326 | + allowRepoList = find_option("repolist",0,0)!=0; | |
| 2274 | 2327 | zAltBase = find_option("baseurl", 0, 1); |
| 2275 | 2328 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2276 | 2329 | if( zAltBase ){ |
| 2277 | 2330 | set_base_url(zAltBase); |
| 2278 | 2331 | } |
| @@ -2286,12 +2339,13 @@ | ||
| 2286 | 2339 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 2287 | 2340 | isUiCmd = g.argv[1][0]=='u'; |
| 2288 | 2341 | if( isUiCmd ){ |
| 2289 | 2342 | flags |= HTTP_SERVER_LOCALHOST; |
| 2290 | 2343 | g.useLocalauth = 1; |
| 2344 | + allowRepoList = 1; | |
| 2291 | 2345 | } |
| 2292 | - find_server_repository(isUiCmd && zNotFound==0, 2); | |
| 2346 | + find_server_repository(2); | |
| 2293 | 2347 | if( zPort ){ |
| 2294 | 2348 | int i; |
| 2295 | 2349 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2296 | 2350 | if( i>0 ){ |
| 2297 | 2351 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2341,18 +2395,18 @@ | ||
| 2341 | 2395 | g.httpOut = stdout; |
| 2342 | 2396 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2343 | 2397 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2344 | 2398 | } |
| 2345 | 2399 | g.cgiOutput = 1; |
| 2346 | - find_server_repository(isUiCmd && zNotFound==0, 2); | |
| 2400 | + find_server_repository(2); | |
| 2347 | 2401 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2348 | 2402 | if( flags & HTTP_SERVER_SCGI ){ |
| 2349 | 2403 | cgi_handle_scgi_request(); |
| 2350 | 2404 | }else{ |
| 2351 | 2405 | cgi_handle_http_request(0); |
| 2352 | 2406 | } |
| 2353 | - process_one_web_page(zNotFound, glob_create(zFileGlob)); | |
| 2407 | + process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); | |
| 2354 | 2408 | #else |
| 2355 | 2409 | /* Win32 implementation */ |
| 2356 | 2410 | if( isUiCmd ){ |
| 2357 | 2411 | zBrowser = db_get("web-browser", "start"); |
| 2358 | 2412 | if( zIpAddr ){ |
| 2359 | 2413 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -1408,10 +1408,48 @@ | |
| 1408 | } |
| 1409 | } |
| 1410 | #endif |
| 1411 | return zRepo; |
| 1412 | } |
| 1413 | |
| 1414 | /* |
| 1415 | ** Preconditions: |
| 1416 | ** |
| 1417 | ** * Environment variables are set up according to the CGI standard. |
| @@ -1431,11 +1469,15 @@ | |
| 1431 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1432 | ** returned as static text. |
| 1433 | ** |
| 1434 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1435 | */ |
| 1436 | static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){ |
| 1437 | const char *zPathInfo; |
| 1438 | char *zPath = NULL; |
| 1439 | int idx; |
| 1440 | int i; |
| 1441 | |
| @@ -1506,10 +1548,12 @@ | |
| 1506 | |
| 1507 | if( szFile<1024 ){ |
| 1508 | set_base_url(0); |
| 1509 | if( zNotFound ){ |
| 1510 | cgi_redirect(zNotFound); |
| 1511 | }else{ |
| 1512 | #ifdef FOSSIL_ENABLE_JSON |
| 1513 | if(g.json.isJsonMode){ |
| 1514 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1515 | return; |
| @@ -1805,10 +1849,11 @@ | |
| 1805 | const char *zFile; |
| 1806 | const char *zNotFound = 0; |
| 1807 | char **azRedirect = 0; /* List of repositories to redirect to */ |
| 1808 | int nRedirect = 0; /* Number of entries in azRedirect */ |
| 1809 | Glob *pFileGlob = 0; /* Pattern for files */ |
| 1810 | Blob config, line, key, value, value2; |
| 1811 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 1812 | zFile = g.argv[2]; |
| 1813 | }else{ |
| 1814 | zFile = g.argv[1]; |
| @@ -1862,10 +1907,19 @@ | |
| 1862 | ** Grant "administrator" privileges to users connecting with HTTP |
| 1863 | ** from IP address 127.0.0.1. Do not bother checking credentials. |
| 1864 | */ |
| 1865 | g.useLocalauth = 1; |
| 1866 | continue; |
| 1867 | } |
| 1868 | if( blob_eq(&key, "redirect:") && blob_token(&line, &value) |
| 1869 | && blob_token(&line, &value2) ){ |
| 1870 | /* See the header comment on the redirect_web_page() function |
| 1871 | ** above for details. */ |
| @@ -1952,11 +2006,11 @@ | |
| 1952 | } |
| 1953 | cgi_init(); |
| 1954 | if( nRedirect ){ |
| 1955 | redirect_web_page(nRedirect, azRedirect); |
| 1956 | }else{ |
| 1957 | process_one_web_page(zNotFound, pFileGlob); |
| 1958 | } |
| 1959 | } |
| 1960 | |
| 1961 | /* |
| 1962 | ** If g.argv[arg] exists then it is either the name of a repository |
| @@ -1970,24 +2024,17 @@ | |
| 1970 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 1971 | ** a directory full of repositories, then set g.zRepositoryName to |
| 1972 | ** the name of that directory and the specific repository will be |
| 1973 | ** opened later by process_one_web_page() based on the content of |
| 1974 | ** the PATH_INFO variable. |
| 1975 | ** |
| 1976 | ** If disallowDir is set, then the directory full of repositories method |
| 1977 | ** is disallowed. |
| 1978 | */ |
| 1979 | static void find_server_repository(int disallowDir, int arg){ |
| 1980 | if( g.argc<=arg ){ |
| 1981 | db_must_be_within_tree(); |
| 1982 | }else if( file_isdir(g.argv[arg])==1 ){ |
| 1983 | if( disallowDir ){ |
| 1984 | fossil_fatal("\"%s\" is a directory, not a repository file", g.argv[arg]); |
| 1985 | }else{ |
| 1986 | g.zRepositoryName = mprintf("%s", g.argv[arg]); |
| 1987 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 1988 | } |
| 1989 | }else{ |
| 1990 | db_open_repository(g.argv[arg]); |
| 1991 | } |
| 1992 | } |
| 1993 | |
| @@ -2028,18 +2075,19 @@ | |
| 2028 | ** If the --localauth option is given, then automatic login is performed |
| 2029 | ** for requests coming from localhost, if the "localauth" setting is not |
| 2030 | ** enabled. |
| 2031 | ** |
| 2032 | ** Options: |
| 2033 | ** --localauth enable automatic login for local connections |
| 2034 | ** --host NAME specify hostname of the server |
| 2035 | ** --https signal a request coming in via https |
| 2036 | ** --nojail drop root privilege but do not enter the chroot jail |
| 2037 | ** --nossl signal that no SSL connections are available |
| 2038 | ** --notfound URL use URL as "HTTP 404, object not found" page. |
| 2039 | ** --files GLOB comma-separate glob patterns for static file to serve |
| 2040 | ** --baseurl URL base URL (useful with reverse proxies) |
| 2041 | ** --scgi Interpret input as SCGI rather than HTTP |
| 2042 | ** --skin LABEL Use override skin LABEL |
| 2043 | ** |
| 2044 | ** See also: cgi, server, winsrv |
| 2045 | */ |
| @@ -2049,10 +2097,11 @@ | |
| 2049 | const char *zHost; |
| 2050 | const char *zAltBase; |
| 2051 | const char *zFileGlob; |
| 2052 | int useSCGI; |
| 2053 | int noJail; |
| 2054 | |
| 2055 | /* The winhttp module passes the --files option as --files-urlenc with |
| 2056 | ** the argument being URL encoded, to avoid wildcard expansion in the |
| 2057 | ** shell. This option is for internal use and is undocumented. |
| 2058 | */ |
| @@ -2065,10 +2114,11 @@ | |
| 2065 | zFileGlob = find_option("files",0,1); |
| 2066 | } |
| 2067 | skin_override(); |
| 2068 | zNotFound = find_option("notfound", 0, 1); |
| 2069 | noJail = find_option("nojail",0,0)!=0; |
| 2070 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2071 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2072 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2073 | zAltBase = find_option("baseurl", 0, 1); |
| 2074 | if( zAltBase ) set_base_url(zAltBase); |
| @@ -2089,15 +2139,15 @@ | |
| 2089 | g.fullHttpReply = 1; |
| 2090 | if( g.argc>=5 ){ |
| 2091 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2092 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2093 | zIpAddr = g.argv[4]; |
| 2094 | find_server_repository(0, 5); |
| 2095 | }else{ |
| 2096 | g.httpIn = stdin; |
| 2097 | g.httpOut = stdout; |
| 2098 | find_server_repository(0, 2); |
| 2099 | } |
| 2100 | if( zIpAddr==0 ){ |
| 2101 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2102 | if( zIpAddr && zIpAddr[0] ){ |
| 2103 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2109,21 +2159,21 @@ | |
| 2109 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2110 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2111 | }else{ |
| 2112 | cgi_handle_http_request(zIpAddr); |
| 2113 | } |
| 2114 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 2115 | } |
| 2116 | |
| 2117 | /* |
| 2118 | ** Process all requests in a single SSH connection if possible. |
| 2119 | */ |
| 2120 | void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ |
| 2121 | blob_zero(&g.cgiIn); |
| 2122 | do{ |
| 2123 | cgi_handle_ssh_http_request(zIpAddr); |
| 2124 | process_one_web_page(0, FileGlob); |
| 2125 | blob_reset(&g.cgiIn); |
| 2126 | } while ( g.fSshClient & CGI_SSH_FOSSIL || |
| 2127 | g.fSshClient & CGI_SSH_COMPAT ); |
| 2128 | } |
| 2129 | |
| @@ -2140,21 +2190,21 @@ | |
| 2140 | Th_InitTraceLog(); |
| 2141 | login_set_capabilities("sx", 0); |
| 2142 | g.useLocalauth = 1; |
| 2143 | g.httpIn = stdin; |
| 2144 | g.httpOut = stdout; |
| 2145 | find_server_repository(0, 2); |
| 2146 | g.cgiOutput = 1; |
| 2147 | g.fullHttpReply = 1; |
| 2148 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2149 | if( zIpAddr && zIpAddr[0] ){ |
| 2150 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2151 | ssh_request_loop(zIpAddr, 0); |
| 2152 | }else{ |
| 2153 | cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); |
| 2154 | cgi_handle_http_request(0); |
| 2155 | process_one_web_page(0, 0); |
| 2156 | } |
| 2157 | } |
| 2158 | |
| 2159 | #if !defined(_WIN32) |
| 2160 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| @@ -2227,10 +2277,11 @@ | |
| 2227 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2228 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2229 | ** --notfound URL Redirect |
| 2230 | ** -P|--port TCPPORT listen to request on port TCPPORT |
| 2231 | ** --th-trace trace TH1 execution (for debugging purposes) |
| 2232 | ** --scgi Accept SCGI rather than HTTP |
| 2233 | ** --skin LABEL Use override skin LABEL |
| 2234 | |
| 2235 | ** |
| 2236 | ** See also: cgi, http, winsrv |
| @@ -2244,10 +2295,11 @@ | |
| 2244 | const char *zNotFound; /* The --notfound option or NULL */ |
| 2245 | int flags = 0; /* Server flags */ |
| 2246 | #if !defined(_WIN32) |
| 2247 | int noJail; /* Do not enter the chroot jail */ |
| 2248 | #endif |
| 2249 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2250 | const char *zFileGlob; /* Static content must match this */ |
| 2251 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2252 | |
| 2253 | #if defined(_WIN32) |
| @@ -2269,10 +2321,11 @@ | |
| 2269 | #endif |
| 2270 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2271 | Th_InitTraceLog(); |
| 2272 | zPort = find_option("port", "P", 1); |
| 2273 | zNotFound = find_option("notfound", 0, 1); |
| 2274 | zAltBase = find_option("baseurl", 0, 1); |
| 2275 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2276 | if( zAltBase ){ |
| 2277 | set_base_url(zAltBase); |
| 2278 | } |
| @@ -2286,12 +2339,13 @@ | |
| 2286 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 2287 | isUiCmd = g.argv[1][0]=='u'; |
| 2288 | if( isUiCmd ){ |
| 2289 | flags |= HTTP_SERVER_LOCALHOST; |
| 2290 | g.useLocalauth = 1; |
| 2291 | } |
| 2292 | find_server_repository(isUiCmd && zNotFound==0, 2); |
| 2293 | if( zPort ){ |
| 2294 | int i; |
| 2295 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2296 | if( i>0 ){ |
| 2297 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2341,18 +2395,18 @@ | |
| 2341 | g.httpOut = stdout; |
| 2342 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2343 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2344 | } |
| 2345 | g.cgiOutput = 1; |
| 2346 | find_server_repository(isUiCmd && zNotFound==0, 2); |
| 2347 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2348 | if( flags & HTTP_SERVER_SCGI ){ |
| 2349 | cgi_handle_scgi_request(); |
| 2350 | }else{ |
| 2351 | cgi_handle_http_request(0); |
| 2352 | } |
| 2353 | process_one_web_page(zNotFound, glob_create(zFileGlob)); |
| 2354 | #else |
| 2355 | /* Win32 implementation */ |
| 2356 | if( isUiCmd ){ |
| 2357 | zBrowser = db_get("web-browser", "start"); |
| 2358 | if( zIpAddr ){ |
| 2359 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -1408,10 +1408,48 @@ | |
| 1408 | } |
| 1409 | } |
| 1410 | #endif |
| 1411 | return zRepo; |
| 1412 | } |
| 1413 | |
| 1414 | /* |
| 1415 | ** Generate a web-page that lists all repositories located under the |
| 1416 | ** g.zRepositoryName directory and return non-zero. |
| 1417 | ** |
| 1418 | ** Or, if no repositories can be located beneath g.zRepositoryName, |
| 1419 | ** return 0. |
| 1420 | */ |
| 1421 | static int repo_list_page(void){ |
| 1422 | Blob base; |
| 1423 | int n = 0; |
| 1424 | |
| 1425 | assert( g.db==0 ); |
| 1426 | blob_init(&base, g.zRepositoryName, -1); |
| 1427 | sqlite3_open(":memory:", &g.db); |
| 1428 | db_multi_exec("CREATE TABLE sfile(x TEXT);"); |
| 1429 | db_multi_exec("CREATE TABLE vfile(pathname);"); |
| 1430 | vfile_scan(&base, blob_size(&base), 0, 0, 0); |
| 1431 | db_multi_exec("DELETE FROM sfile WHERE x NOT GLOB '*.fossil'"); |
| 1432 | n = db_int(0, "SELECT count(*) FROM sfile"); |
| 1433 | if( n>0 ){ |
| 1434 | Stmt q; |
| 1435 | @ <h1>Available Repositories:</h1> |
| 1436 | @ <ol> |
| 1437 | db_prepare(&q, "SELECT x, substr(x,-7,-100000)||'/home'" |
| 1438 | " FROM sfile ORDER BY x COLLATE nocase;"); |
| 1439 | while( db_step(&q)==SQLITE_ROW ){ |
| 1440 | const char *zName = db_column_text(&q, 0); |
| 1441 | const char *zUrl = db_column_text(&q, 1); |
| 1442 | @ <li><a href="%h(zUrl)">%h(zName)</a></li> |
| 1443 | } |
| 1444 | @ </ol> |
| 1445 | cgi_reply(); |
| 1446 | } |
| 1447 | sqlite3_close(g.db); |
| 1448 | g.db = 0; |
| 1449 | return n; |
| 1450 | } |
| 1451 | |
| 1452 | /* |
| 1453 | ** Preconditions: |
| 1454 | ** |
| 1455 | ** * Environment variables are set up according to the CGI standard. |
| @@ -1431,11 +1469,15 @@ | |
| 1469 | ** $prefix can be determined from its suffix, then the file $prefix is |
| 1470 | ** returned as static text. |
| 1471 | ** |
| 1472 | ** If no suitable webpage is found, try to redirect to zNotFound. |
| 1473 | */ |
| 1474 | static void process_one_web_page( |
| 1475 | const char *zNotFound, /* Redirect here on a 404 if not NULL */ |
| 1476 | Glob *pFileGlob, /* Deliver static files matching */ |
| 1477 | int allowRepoList /* Send repo list for "/" URL */ |
| 1478 | ){ |
| 1479 | const char *zPathInfo; |
| 1480 | char *zPath = NULL; |
| 1481 | int idx; |
| 1482 | int i; |
| 1483 | |
| @@ -1506,10 +1548,12 @@ | |
| 1548 | |
| 1549 | if( szFile<1024 ){ |
| 1550 | set_base_url(0); |
| 1551 | if( zNotFound ){ |
| 1552 | cgi_redirect(zNotFound); |
| 1553 | }else if( strcmp(zPathInfo,"/")==0 && repo_list_page() ){ |
| 1554 | /* Will return a list of repositories */ |
| 1555 | }else{ |
| 1556 | #ifdef FOSSIL_ENABLE_JSON |
| 1557 | if(g.json.isJsonMode){ |
| 1558 | json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,1); |
| 1559 | return; |
| @@ -1805,10 +1849,11 @@ | |
| 1849 | const char *zFile; |
| 1850 | const char *zNotFound = 0; |
| 1851 | char **azRedirect = 0; /* List of repositories to redirect to */ |
| 1852 | int nRedirect = 0; /* Number of entries in azRedirect */ |
| 1853 | Glob *pFileGlob = 0; /* Pattern for files */ |
| 1854 | int allowRepoList = 0; /* Allow lists of repository files */ |
| 1855 | Blob config, line, key, value, value2; |
| 1856 | if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){ |
| 1857 | zFile = g.argv[2]; |
| 1858 | }else{ |
| 1859 | zFile = g.argv[1]; |
| @@ -1862,10 +1907,19 @@ | |
| 1907 | ** Grant "administrator" privileges to users connecting with HTTP |
| 1908 | ** from IP address 127.0.0.1. Do not bother checking credentials. |
| 1909 | */ |
| 1910 | g.useLocalauth = 1; |
| 1911 | continue; |
| 1912 | } |
| 1913 | if( blob_eq(&key, "repolist") ){ |
| 1914 | /* repolist |
| 1915 | ** |
| 1916 | ** If using "directory:" and the URL is "/" then generate a page |
| 1917 | ** showing a list of available repositories. |
| 1918 | */ |
| 1919 | allowRepoList = 1; |
| 1920 | continue; |
| 1921 | } |
| 1922 | if( blob_eq(&key, "redirect:") && blob_token(&line, &value) |
| 1923 | && blob_token(&line, &value2) ){ |
| 1924 | /* See the header comment on the redirect_web_page() function |
| 1925 | ** above for details. */ |
| @@ -1952,11 +2006,11 @@ | |
| 2006 | } |
| 2007 | cgi_init(); |
| 2008 | if( nRedirect ){ |
| 2009 | redirect_web_page(nRedirect, azRedirect); |
| 2010 | }else{ |
| 2011 | process_one_web_page(zNotFound, pFileGlob, allowRepoList); |
| 2012 | } |
| 2013 | } |
| 2014 | |
| 2015 | /* |
| 2016 | ** If g.argv[arg] exists then it is either the name of a repository |
| @@ -1970,24 +2024,17 @@ | |
| 2024 | ** Open the repository to be served if it is known. If g.argv[arg] is |
| 2025 | ** a directory full of repositories, then set g.zRepositoryName to |
| 2026 | ** the name of that directory and the specific repository will be |
| 2027 | ** opened later by process_one_web_page() based on the content of |
| 2028 | ** the PATH_INFO variable. |
| 2029 | */ |
| 2030 | static void find_server_repository(int arg){ |
| 2031 | if( g.argc<=arg ){ |
| 2032 | db_must_be_within_tree(); |
| 2033 | }else if( file_isdir(g.argv[arg])==1 ){ |
| 2034 | g.zRepositoryName = mprintf("%s", g.argv[arg]); |
| 2035 | file_simplify_name(g.zRepositoryName, -1, 0); |
| 2036 | }else{ |
| 2037 | db_open_repository(g.argv[arg]); |
| 2038 | } |
| 2039 | } |
| 2040 | |
| @@ -2028,18 +2075,19 @@ | |
| 2075 | ** If the --localauth option is given, then automatic login is performed |
| 2076 | ** for requests coming from localhost, if the "localauth" setting is not |
| 2077 | ** enabled. |
| 2078 | ** |
| 2079 | ** Options: |
| 2080 | ** --baseurl URL base URL (useful with reverse proxies) |
| 2081 | ** --files GLOB comma-separate glob patterns for static file to serve |
| 2082 | ** --localauth enable automatic login for local connections |
| 2083 | ** --host NAME specify hostname of the server |
| 2084 | ** --https signal a request coming in via https |
| 2085 | ** --nojail drop root privilege but do not enter the chroot jail |
| 2086 | ** --nossl signal that no SSL connections are available |
| 2087 | ** --notfound URL use URL as "HTTP 404, object not found" page. |
| 2088 | ** --repolist If REPOSITORY is directory, URL "/" lists all repos |
| 2089 | ** --scgi Interpret input as SCGI rather than HTTP |
| 2090 | ** --skin LABEL Use override skin LABEL |
| 2091 | ** |
| 2092 | ** See also: cgi, server, winsrv |
| 2093 | */ |
| @@ -2049,10 +2097,11 @@ | |
| 2097 | const char *zHost; |
| 2098 | const char *zAltBase; |
| 2099 | const char *zFileGlob; |
| 2100 | int useSCGI; |
| 2101 | int noJail; |
| 2102 | int allowRepoList; |
| 2103 | |
| 2104 | /* The winhttp module passes the --files option as --files-urlenc with |
| 2105 | ** the argument being URL encoded, to avoid wildcard expansion in the |
| 2106 | ** shell. This option is for internal use and is undocumented. |
| 2107 | */ |
| @@ -2065,10 +2114,11 @@ | |
| 2114 | zFileGlob = find_option("files",0,1); |
| 2115 | } |
| 2116 | skin_override(); |
| 2117 | zNotFound = find_option("notfound", 0, 1); |
| 2118 | noJail = find_option("nojail",0,0)!=0; |
| 2119 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2120 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2121 | g.sslNotAvailable = find_option("nossl", 0, 0)!=0; |
| 2122 | useSCGI = find_option("scgi", 0, 0)!=0; |
| 2123 | zAltBase = find_option("baseurl", 0, 1); |
| 2124 | if( zAltBase ) set_base_url(zAltBase); |
| @@ -2089,15 +2139,15 @@ | |
| 2139 | g.fullHttpReply = 1; |
| 2140 | if( g.argc>=5 ){ |
| 2141 | g.httpIn = fossil_fopen(g.argv[2], "rb"); |
| 2142 | g.httpOut = fossil_fopen(g.argv[3], "wb"); |
| 2143 | zIpAddr = g.argv[4]; |
| 2144 | find_server_repository(5); |
| 2145 | }else{ |
| 2146 | g.httpIn = stdin; |
| 2147 | g.httpOut = stdout; |
| 2148 | find_server_repository(2); |
| 2149 | } |
| 2150 | if( zIpAddr==0 ){ |
| 2151 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2152 | if( zIpAddr && zIpAddr[0] ){ |
| 2153 | g.fSshClient |= CGI_SSH_CLIENT; |
| @@ -2109,21 +2159,21 @@ | |
| 2159 | }else if( g.fSshClient & CGI_SSH_CLIENT ){ |
| 2160 | ssh_request_loop(zIpAddr, glob_create(zFileGlob)); |
| 2161 | }else{ |
| 2162 | cgi_handle_http_request(zIpAddr); |
| 2163 | } |
| 2164 | process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); |
| 2165 | } |
| 2166 | |
| 2167 | /* |
| 2168 | ** Process all requests in a single SSH connection if possible. |
| 2169 | */ |
| 2170 | void ssh_request_loop(const char *zIpAddr, Glob *FileGlob){ |
| 2171 | blob_zero(&g.cgiIn); |
| 2172 | do{ |
| 2173 | cgi_handle_ssh_http_request(zIpAddr); |
| 2174 | process_one_web_page(0, FileGlob, 0); |
| 2175 | blob_reset(&g.cgiIn); |
| 2176 | } while ( g.fSshClient & CGI_SSH_FOSSIL || |
| 2177 | g.fSshClient & CGI_SSH_COMPAT ); |
| 2178 | } |
| 2179 | |
| @@ -2140,21 +2190,21 @@ | |
| 2190 | Th_InitTraceLog(); |
| 2191 | login_set_capabilities("sx", 0); |
| 2192 | g.useLocalauth = 1; |
| 2193 | g.httpIn = stdin; |
| 2194 | g.httpOut = stdout; |
| 2195 | find_server_repository(2); |
| 2196 | g.cgiOutput = 1; |
| 2197 | g.fullHttpReply = 1; |
| 2198 | zIpAddr = cgi_ssh_remote_addr(0); |
| 2199 | if( zIpAddr && zIpAddr[0] ){ |
| 2200 | g.fSshClient |= CGI_SSH_CLIENT; |
| 2201 | ssh_request_loop(zIpAddr, 0); |
| 2202 | }else{ |
| 2203 | cgi_set_parameter("REMOTE_ADDR", "127.0.0.1"); |
| 2204 | cgi_handle_http_request(0); |
| 2205 | process_one_web_page(0, 0, 0); |
| 2206 | } |
| 2207 | } |
| 2208 | |
| 2209 | #if !defined(_WIN32) |
| 2210 | #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__) |
| @@ -2227,10 +2277,11 @@ | |
| 2277 | ** --localhost listen on 127.0.0.1 only (always true for "ui") |
| 2278 | ** --nojail Drop root privileges but do not enter the chroot jail |
| 2279 | ** --notfound URL Redirect |
| 2280 | ** -P|--port TCPPORT listen to request on port TCPPORT |
| 2281 | ** --th-trace trace TH1 execution (for debugging purposes) |
| 2282 | ** --repolist If REPOSITORY is dir, URL "/" lists repos. |
| 2283 | ** --scgi Accept SCGI rather than HTTP |
| 2284 | ** --skin LABEL Use override skin LABEL |
| 2285 | |
| 2286 | ** |
| 2287 | ** See also: cgi, http, winsrv |
| @@ -2244,10 +2295,11 @@ | |
| 2295 | const char *zNotFound; /* The --notfound option or NULL */ |
| 2296 | int flags = 0; /* Server flags */ |
| 2297 | #if !defined(_WIN32) |
| 2298 | int noJail; /* Do not enter the chroot jail */ |
| 2299 | #endif |
| 2300 | int allowRepoList; /* List repositories on URL "/" */ |
| 2301 | const char *zAltBase; /* Argument to the --baseurl option */ |
| 2302 | const char *zFileGlob; /* Static content must match this */ |
| 2303 | char *zIpAddr = 0; /* Bind to this IP address */ |
| 2304 | |
| 2305 | #if defined(_WIN32) |
| @@ -2269,10 +2321,11 @@ | |
| 2321 | #endif |
| 2322 | g.useLocalauth = find_option("localauth", 0, 0)!=0; |
| 2323 | Th_InitTraceLog(); |
| 2324 | zPort = find_option("port", "P", 1); |
| 2325 | zNotFound = find_option("notfound", 0, 1); |
| 2326 | allowRepoList = find_option("repolist",0,0)!=0; |
| 2327 | zAltBase = find_option("baseurl", 0, 1); |
| 2328 | if( find_option("scgi", 0, 0)!=0 ) flags |= HTTP_SERVER_SCGI; |
| 2329 | if( zAltBase ){ |
| 2330 | set_base_url(zAltBase); |
| 2331 | } |
| @@ -2286,12 +2339,13 @@ | |
| 2339 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 2340 | isUiCmd = g.argv[1][0]=='u'; |
| 2341 | if( isUiCmd ){ |
| 2342 | flags |= HTTP_SERVER_LOCALHOST; |
| 2343 | g.useLocalauth = 1; |
| 2344 | allowRepoList = 1; |
| 2345 | } |
| 2346 | find_server_repository(2); |
| 2347 | if( zPort ){ |
| 2348 | int i; |
| 2349 | for(i=strlen(zPort)-1; i>=0 && zPort[i]!=':'; i--){} |
| 2350 | if( i>0 ){ |
| 2351 | zIpAddr = mprintf("%.*s", i, zPort); |
| @@ -2341,18 +2395,18 @@ | |
| 2395 | g.httpOut = stdout; |
| 2396 | if( g.fHttpTrace || g.fSqlTrace ){ |
| 2397 | fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); |
| 2398 | } |
| 2399 | g.cgiOutput = 1; |
| 2400 | find_server_repository(2); |
| 2401 | g.zRepositoryName = enter_chroot_jail(g.zRepositoryName, noJail); |
| 2402 | if( flags & HTTP_SERVER_SCGI ){ |
| 2403 | cgi_handle_scgi_request(); |
| 2404 | }else{ |
| 2405 | cgi_handle_http_request(0); |
| 2406 | } |
| 2407 | process_one_web_page(zNotFound, glob_create(zFileGlob), allowRepoList); |
| 2408 | #else |
| 2409 | /* Win32 implementation */ |
| 2410 | if( isUiCmd ){ |
| 2411 | zBrowser = db_get("web-browser", "start"); |
| 2412 | if( zIpAddr ){ |
| 2413 |