Fossil SCM

Security: Do not serve static files using the "http", "server", or "ui" commands unless the --files option appears and specifies a comma-separated list of GLOB expressions that match all files to be served.

drh 2012-12-05 15:45 trunk
Commit 2c8557cc7a1147de0ca5cad4ea87ff5250ab8257
2 files changed +59 -20 +12 -2
+59 -20
--- src/main.c
+++ src/main.c
@@ -1258,12 +1258,22 @@
12581258
** then g.zRepositoryName holds the directory that contains the repository
12591259
** and the actual repository is taken from the first element of PATH_INFO.
12601260
**
12611261
** Process the webpage specified by the PATH_INFO or REQUEST_URI
12621262
** environment variable.
1263
+**
1264
+** If the repository is not known, the a search is done through the
1265
+** file hierarchy rooted at g.zRepositoryName for a suitable repository
1266
+** with a name of $prefix.fossil, where $prefix is any prefix of PATH_INFO.
1267
+** Or, if an ordinary file named $prefix is found, and $prefix matches
1268
+** pFileGlob and $prefix does not match "*.fossil*" and the mimetype of
1269
+** $prefix can be determined from its suffix, then the file $prefix is
1270
+** returned as static text.
1271
+**
1272
+** If no suitable webpage is found, try to redirect to zNotFound.
12631273
*/
1264
-static void process_one_web_page(const char *zNotFound){
1274
+static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){
12651275
const char *zPathInfo;
12661276
char *zPath = NULL;
12671277
int idx;
12681278
int i;
12691279
@@ -1313,11 +1323,13 @@
13131323
if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){
13141324
fossil_free(zToFree);
13151325
i++;
13161326
continue;
13171327
}
1318
- if( file_isfile(zRepo)
1328
+ if( pFileGlob!=0
1329
+ && file_isfile(zRepo)
1330
+ && glob_match(pFileGlob, zRepo)
13191331
&& strglob("*.fossil*",zRepo)==0
13201332
&& (zMimetype = mimetype_from_name(zRepo))!=0
13211333
&& strcmp(zMimetype, "application/x-fossil-artifact")!=0
13221334
){
13231335
Blob content;
@@ -1527,10 +1539,11 @@
15271539
void cmd_cgi(void){
15281540
const char *zFile;
15291541
const char *zNotFound = 0;
15301542
char **azRedirect = 0; /* List of repositories to redirect to */
15311543
int nRedirect = 0; /* Number of entries in azRedirect */
1544
+ Glob *pFileGlob = 0; /* Pattern for files */
15321545
Blob config, line, key, value, value2;
15331546
if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
15341547
zFile = g.argv[2];
15351548
}else{
15361549
zFile = g.argv[1];
@@ -1583,20 +1596,24 @@
15831596
azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
15841597
blob_reset(&value);
15851598
blob_reset(&value2);
15861599
continue;
15871600
}
1601
+ if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
1602
+ pFileGlob = glob_create(blob_str(&value));
1603
+ continue;
1604
+ }
15881605
}
15891606
blob_reset(&config);
15901607
if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
15911608
cgi_panic("Unable to find or open the project repository");
15921609
}
15931610
cgi_init();
15941611
if( nRedirect ){
15951612
redirect_web_page(nRedirect, azRedirect);
15961613
}else{
1597
- process_one_web_page(zNotFound);
1614
+ process_one_web_page(zNotFound, pFileGlob);
15981615
}
15991616
}
16001617
16011618
/* If the CGI program contains one or more lines of the form
16021619
**
@@ -1696,21 +1713,22 @@
16961713
** Handle a single HTTP request appearing on stdin. The resulting webpage
16971714
** is delivered on stdout. This method is used to launch an HTTP request
16981715
** handler from inetd, for example. The argument is the name of the
16991716
** repository.
17001717
**
1701
-** If REPOSITORY is a directory that contains one or more repositories
1702
-** with names of the form "*.fossil" then the first element of the URL
1703
-** pathname selects among the various repositories. If the pathname does
1718
+** If REPOSITORY is a directory that contains one or more repositories,
1719
+** either directly in REPOSITORY itself, or in subdirectories, and
1720
+** with names of the form "*.fossil" then the a prefix of the URL pathname
1721
+** selects from among the various repositories. If the pathname does
17041722
** not select a valid repository and the --notfound option is available,
17051723
** then the server redirects (HTTP code 302) to the URL of --notfound.
17061724
** When REPOSITORY is a directory, the pathname must contain only
17071725
** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/"
17081726
** and every "." must be surrounded on both sides by alphanumerics or else
17091727
** a 404 error is returned. Static content files in the directory are
1710
-** returned if they have a well-known suffix. Repository files and their
1711
-** journals are never returned as static content.
1728
+** returned if they match comma-separate GLOB pattern specified by --files
1729
+** and do not match "*.fossil*" and have a well-known suffix.
17121730
**
17131731
** The --host option can be used to specify the hostname for the server.
17141732
** The --https option indicates that the request came from HTTPS rather
17151733
** than HTTP. If --nossl is given, then SSL connections will not be available,
17161734
** thus also no redirecting from http: to https: will take place.
@@ -1723,19 +1741,34 @@
17231741
** --localauth enable automatic login for local connections
17241742
** --host NAME specify hostname of the server
17251743
** --https signal a request coming in via https
17261744
** --nossl signal that no SSL connections are available
17271745
** --notfound URL use URL as "HTTP 404, object not found" page.
1746
+** --files GLOB comma-separate glob patterns for static file to serve
17281747
** --baseurl URL base URL (useful with reverse proxies)
17291748
**
17301749
** See also: cgi, server, winsrv
17311750
*/
17321751
void cmd_http(void){
17331752
const char *zIpAddr;
17341753
const char *zNotFound;
17351754
const char *zHost;
17361755
const char *zAltBase;
1756
+ const char *zFileGlob;
1757
+
1758
+ /* The winhttp module passes the --files option as --files-urlenc with
1759
+ ** the argument being URL encoded, to avoid wildcard expansion in the
1760
+ ** shell. This option is for internal use and is undocumented.
1761
+ */
1762
+ zFileGlob = find_option("files-urlenc",0,1);
1763
+ if( zFileGlob ){
1764
+ char *z = mprintf("%s", zFileGlob);
1765
+ dehttpize(z);
1766
+ zFileGlob = z;
1767
+ }else{
1768
+ zFileGlob = find_option("files",0,1);
1769
+ }
17371770
zNotFound = find_option("notfound", 0, 1);
17381771
g.useLocalauth = find_option("localauth", 0, 0)!=0;
17391772
g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
17401773
zAltBase = find_option("baseurl", 0, 1);
17411774
if( zAltBase ) set_base_url(zAltBase);
@@ -1757,11 +1790,11 @@
17571790
zIpAddr = 0;
17581791
}
17591792
find_server_repository(0);
17601793
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
17611794
cgi_handle_http_request(zIpAddr);
1762
- process_one_web_page(zNotFound);
1795
+ process_one_web_page(zNotFound, glob_create(zFileGlob));
17631796
}
17641797
17651798
/*
17661799
** Note that the following command is used by ssh:// processing.
17671800
**
@@ -1780,11 +1813,11 @@
17801813
g.httpOut = stdout;
17811814
find_server_repository(0);
17821815
g.cgiOutput = 1;
17831816
g.fullHttpReply = 1;
17841817
cgi_handle_http_request(0);
1785
- process_one_web_page(0);
1818
+ process_one_web_page(0, 0);
17861819
}
17871820
17881821
#if !defined(_WIN32)
17891822
#if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
17901823
/*
@@ -1825,20 +1858,23 @@
18251858
**
18261859
** The "ui" command automatically starts a web browser after initializing
18271860
** the web server. The "ui" command also binds to 127.0.0.1 and so will
18281861
** only process HTTP traffic from the local machine.
18291862
**
1830
-** In the "server" command, the REPOSITORY can be a directory (aka folder)
1831
-** that contains one or more repositories with names ending in ".fossil".
1832
-** In that case, the first element of the URL is used to select among the
1833
-** various repositories. To thwart mischief, the pathname in the URL must
1863
+** The REPOSITORY can be a directory (aka folder) that contains one or
1864
+** more repositories with names ending in ".fossil". In this case, the
1865
+** a prefix of the URL pathname is used to search the directory for an
1866
+** appropriate repository. To thwart mischief, the pathname in the URL must
18341867
** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
18351868
** occur after "/", and every "." must be surrounded on both sides by
18361869
** alphanumerics. Any pathname that does not satisfy these constraints
1837
-** results in a 404 error. Files in REPOSITORY that have known suffixes
1838
-** such as ".txt" or ".html" or ".jpeg" (but not ".fossil"!) will be
1839
-** served as static content.
1870
+** results in a 404 error. Files in REPOSITORY that match the comma-separated
1871
+** list of glob patterns given by --files and that have known suffixes
1872
+** such as ".txt" or ".html" or ".jpeg" and do not match the pattern
1873
+** "*.fossil*" will be served as static content. With the "ui" command,
1874
+** the REPOSITORY can only be a directory if the --notfound option is
1875
+** also present.
18401876
**
18411877
** By default, the "ui" command provides full administrative access without
18421878
** having to log in. This can be disabled by setting turning off the
18431879
** "localauth" setting. Automatic login for the "server" command is available
18441880
** if the --localauth option is present and the "localauth" setting is off
@@ -1850,10 +1886,11 @@
18501886
** --localauth enable automatic login for requests from localhost
18511887
** -P|--port TCPPORT listen to request on port TCPPORT
18521888
** --th-trace trace TH1 execution (for debugging purposes)
18531889
** --baseurl URL Use URL as the base (useful for reverse proxies)
18541890
** --notfound URL Redirect
1891
+** --files GLOBLIST Comma-separated list of glob patterns for static files
18551892
**
18561893
** See also: cgi, http, winsrv
18571894
*/
18581895
void cmd_webserver(void){
18591896
int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1862,16 +1899,18 @@
18621899
char *zBrowserCmd = 0; /* Command to launch the web browser */
18631900
int isUiCmd; /* True if command is "ui", not "server' */
18641901
const char *zNotFound; /* The --notfound option or NULL */
18651902
int flags = 0; /* Server flags */
18661903
const char *zAltBase; /* Argument to the --baseurl option */
1904
+ const char *zFileGlob; /* Static content must match this */
18671905
18681906
#if defined(_WIN32)
18691907
const char *zStopperFile; /* Name of file used to terminate server */
18701908
zStopperFile = find_option("stopper", 0, 1);
18711909
#endif
18721910
1911
+ zFileGlob = find_option("files", 0, 1);
18731912
g.thTrace = find_option("th-trace", 0, 0)!=0;
18741913
g.useLocalauth = find_option("localauth", 0, 0)!=0;
18751914
if( g.thTrace ){
18761915
blob_zero(&g.thLog);
18771916
}
@@ -1927,21 +1966,21 @@
19271966
}
19281967
g.cgiOutput = 1;
19291968
find_server_repository(isUiCmd && zNotFound==0);
19301969
g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
19311970
cgi_handle_http_request(0);
1932
- process_one_web_page(zNotFound);
1971
+ process_one_web_page(zNotFound, glob_create(zFileGlob));
19331972
#else
19341973
/* Win32 implementation */
19351974
if( isUiCmd ){
19361975
zBrowser = db_get("web-browser", "start");
19371976
zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
19381977
}
19391978
db_close(1);
1940
- if( win32_http_service(iPort, zNotFound, flags) ){
1979
+ if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){
19411980
win32_http_server(iPort, mxPort, zBrowserCmd,
1942
- zStopperFile, zNotFound, flags);
1981
+ zStopperFile, zNotFound, zFileGlob, flags);
19431982
}
19441983
#endif
19451984
}
19461985
19471986
/*
19481987
--- src/main.c
+++ src/main.c
@@ -1258,12 +1258,22 @@
1258 ** then g.zRepositoryName holds the directory that contains the repository
1259 ** and the actual repository is taken from the first element of PATH_INFO.
1260 **
1261 ** Process the webpage specified by the PATH_INFO or REQUEST_URI
1262 ** environment variable.
 
 
 
 
 
 
 
 
 
 
1263 */
1264 static void process_one_web_page(const char *zNotFound){
1265 const char *zPathInfo;
1266 char *zPath = NULL;
1267 int idx;
1268 int i;
1269
@@ -1313,11 +1323,13 @@
1313 if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){
1314 fossil_free(zToFree);
1315 i++;
1316 continue;
1317 }
1318 if( file_isfile(zRepo)
 
 
1319 && strglob("*.fossil*",zRepo)==0
1320 && (zMimetype = mimetype_from_name(zRepo))!=0
1321 && strcmp(zMimetype, "application/x-fossil-artifact")!=0
1322 ){
1323 Blob content;
@@ -1527,10 +1539,11 @@
1527 void cmd_cgi(void){
1528 const char *zFile;
1529 const char *zNotFound = 0;
1530 char **azRedirect = 0; /* List of repositories to redirect to */
1531 int nRedirect = 0; /* Number of entries in azRedirect */
 
1532 Blob config, line, key, value, value2;
1533 if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
1534 zFile = g.argv[2];
1535 }else{
1536 zFile = g.argv[1];
@@ -1583,20 +1596,24 @@
1583 azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1584 blob_reset(&value);
1585 blob_reset(&value2);
1586 continue;
1587 }
 
 
 
 
1588 }
1589 blob_reset(&config);
1590 if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
1591 cgi_panic("Unable to find or open the project repository");
1592 }
1593 cgi_init();
1594 if( nRedirect ){
1595 redirect_web_page(nRedirect, azRedirect);
1596 }else{
1597 process_one_web_page(zNotFound);
1598 }
1599 }
1600
1601 /* If the CGI program contains one or more lines of the form
1602 **
@@ -1696,21 +1713,22 @@
1696 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1697 ** is delivered on stdout. This method is used to launch an HTTP request
1698 ** handler from inetd, for example. The argument is the name of the
1699 ** repository.
1700 **
1701 ** If REPOSITORY is a directory that contains one or more repositories
1702 ** with names of the form "*.fossil" then the first element of the URL
1703 ** pathname selects among the various repositories. If the pathname does
 
1704 ** not select a valid repository and the --notfound option is available,
1705 ** then the server redirects (HTTP code 302) to the URL of --notfound.
1706 ** When REPOSITORY is a directory, the pathname must contain only
1707 ** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/"
1708 ** and every "." must be surrounded on both sides by alphanumerics or else
1709 ** a 404 error is returned. Static content files in the directory are
1710 ** returned if they have a well-known suffix. Repository files and their
1711 ** journals are never returned as static content.
1712 **
1713 ** The --host option can be used to specify the hostname for the server.
1714 ** The --https option indicates that the request came from HTTPS rather
1715 ** than HTTP. If --nossl is given, then SSL connections will not be available,
1716 ** thus also no redirecting from http: to https: will take place.
@@ -1723,19 +1741,34 @@
1723 ** --localauth enable automatic login for local connections
1724 ** --host NAME specify hostname of the server
1725 ** --https signal a request coming in via https
1726 ** --nossl signal that no SSL connections are available
1727 ** --notfound URL use URL as "HTTP 404, object not found" page.
 
1728 ** --baseurl URL base URL (useful with reverse proxies)
1729 **
1730 ** See also: cgi, server, winsrv
1731 */
1732 void cmd_http(void){
1733 const char *zIpAddr;
1734 const char *zNotFound;
1735 const char *zHost;
1736 const char *zAltBase;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1737 zNotFound = find_option("notfound", 0, 1);
1738 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1739 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1740 zAltBase = find_option("baseurl", 0, 1);
1741 if( zAltBase ) set_base_url(zAltBase);
@@ -1757,11 +1790,11 @@
1757 zIpAddr = 0;
1758 }
1759 find_server_repository(0);
1760 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1761 cgi_handle_http_request(zIpAddr);
1762 process_one_web_page(zNotFound);
1763 }
1764
1765 /*
1766 ** Note that the following command is used by ssh:// processing.
1767 **
@@ -1780,11 +1813,11 @@
1780 g.httpOut = stdout;
1781 find_server_repository(0);
1782 g.cgiOutput = 1;
1783 g.fullHttpReply = 1;
1784 cgi_handle_http_request(0);
1785 process_one_web_page(0);
1786 }
1787
1788 #if !defined(_WIN32)
1789 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1790 /*
@@ -1825,20 +1858,23 @@
1825 **
1826 ** The "ui" command automatically starts a web browser after initializing
1827 ** the web server. The "ui" command also binds to 127.0.0.1 and so will
1828 ** only process HTTP traffic from the local machine.
1829 **
1830 ** In the "server" command, the REPOSITORY can be a directory (aka folder)
1831 ** that contains one or more repositories with names ending in ".fossil".
1832 ** In that case, the first element of the URL is used to select among the
1833 ** various repositories. To thwart mischief, the pathname in the URL must
1834 ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
1835 ** occur after "/", and every "." must be surrounded on both sides by
1836 ** alphanumerics. Any pathname that does not satisfy these constraints
1837 ** results in a 404 error. Files in REPOSITORY that have known suffixes
1838 ** such as ".txt" or ".html" or ".jpeg" (but not ".fossil"!) will be
1839 ** served as static content.
 
 
 
1840 **
1841 ** By default, the "ui" command provides full administrative access without
1842 ** having to log in. This can be disabled by setting turning off the
1843 ** "localauth" setting. Automatic login for the "server" command is available
1844 ** if the --localauth option is present and the "localauth" setting is off
@@ -1850,10 +1886,11 @@
1850 ** --localauth enable automatic login for requests from localhost
1851 ** -P|--port TCPPORT listen to request on port TCPPORT
1852 ** --th-trace trace TH1 execution (for debugging purposes)
1853 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1854 ** --notfound URL Redirect
 
1855 **
1856 ** See also: cgi, http, winsrv
1857 */
1858 void cmd_webserver(void){
1859 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1862,16 +1899,18 @@
1862 char *zBrowserCmd = 0; /* Command to launch the web browser */
1863 int isUiCmd; /* True if command is "ui", not "server' */
1864 const char *zNotFound; /* The --notfound option or NULL */
1865 int flags = 0; /* Server flags */
1866 const char *zAltBase; /* Argument to the --baseurl option */
 
1867
1868 #if defined(_WIN32)
1869 const char *zStopperFile; /* Name of file used to terminate server */
1870 zStopperFile = find_option("stopper", 0, 1);
1871 #endif
1872
 
1873 g.thTrace = find_option("th-trace", 0, 0)!=0;
1874 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1875 if( g.thTrace ){
1876 blob_zero(&g.thLog);
1877 }
@@ -1927,21 +1966,21 @@
1927 }
1928 g.cgiOutput = 1;
1929 find_server_repository(isUiCmd && zNotFound==0);
1930 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1931 cgi_handle_http_request(0);
1932 process_one_web_page(zNotFound);
1933 #else
1934 /* Win32 implementation */
1935 if( isUiCmd ){
1936 zBrowser = db_get("web-browser", "start");
1937 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
1938 }
1939 db_close(1);
1940 if( win32_http_service(iPort, zNotFound, flags) ){
1941 win32_http_server(iPort, mxPort, zBrowserCmd,
1942 zStopperFile, zNotFound, flags);
1943 }
1944 #endif
1945 }
1946
1947 /*
1948
--- src/main.c
+++ src/main.c
@@ -1258,12 +1258,22 @@
1258 ** then g.zRepositoryName holds the directory that contains the repository
1259 ** and the actual repository is taken from the first element of PATH_INFO.
1260 **
1261 ** Process the webpage specified by the PATH_INFO or REQUEST_URI
1262 ** environment variable.
1263 **
1264 ** If the repository is not known, the a search is done through the
1265 ** file hierarchy rooted at g.zRepositoryName for a suitable repository
1266 ** with a name of $prefix.fossil, where $prefix is any prefix of PATH_INFO.
1267 ** Or, if an ordinary file named $prefix is found, and $prefix matches
1268 ** pFileGlob and $prefix does not match "*.fossil*" and the mimetype of
1269 ** $prefix can be determined from its suffix, then the file $prefix is
1270 ** returned as static text.
1271 **
1272 ** If no suitable webpage is found, try to redirect to zNotFound.
1273 */
1274 static void process_one_web_page(const char *zNotFound, Glob *pFileGlob){
1275 const char *zPathInfo;
1276 char *zPath = NULL;
1277 int idx;
1278 int i;
1279
@@ -1313,11 +1323,13 @@
1323 if( zPathInfo[i]=='/' && file_isdir(zRepo)==1 ){
1324 fossil_free(zToFree);
1325 i++;
1326 continue;
1327 }
1328 if( pFileGlob!=0
1329 && file_isfile(zRepo)
1330 && glob_match(pFileGlob, zRepo)
1331 && strglob("*.fossil*",zRepo)==0
1332 && (zMimetype = mimetype_from_name(zRepo))!=0
1333 && strcmp(zMimetype, "application/x-fossil-artifact")!=0
1334 ){
1335 Blob content;
@@ -1527,10 +1539,11 @@
1539 void cmd_cgi(void){
1540 const char *zFile;
1541 const char *zNotFound = 0;
1542 char **azRedirect = 0; /* List of repositories to redirect to */
1543 int nRedirect = 0; /* Number of entries in azRedirect */
1544 Glob *pFileGlob = 0; /* Pattern for files */
1545 Blob config, line, key, value, value2;
1546 if( g.argc==3 && fossil_strcmp(g.argv[1],"cgi")==0 ){
1547 zFile = g.argv[2];
1548 }else{
1549 zFile = g.argv[1];
@@ -1583,20 +1596,24 @@
1596 azRedirect[nRedirect*2-1] = mprintf("%s", blob_str(&value2));
1597 blob_reset(&value);
1598 blob_reset(&value2);
1599 continue;
1600 }
1601 if( blob_eq(&key, "files:") && blob_token(&line, &value) ){
1602 pFileGlob = glob_create(blob_str(&value));
1603 continue;
1604 }
1605 }
1606 blob_reset(&config);
1607 if( g.db==0 && g.zRepositoryName==0 && nRedirect==0 ){
1608 cgi_panic("Unable to find or open the project repository");
1609 }
1610 cgi_init();
1611 if( nRedirect ){
1612 redirect_web_page(nRedirect, azRedirect);
1613 }else{
1614 process_one_web_page(zNotFound, pFileGlob);
1615 }
1616 }
1617
1618 /* If the CGI program contains one or more lines of the form
1619 **
@@ -1696,21 +1713,22 @@
1713 ** Handle a single HTTP request appearing on stdin. The resulting webpage
1714 ** is delivered on stdout. This method is used to launch an HTTP request
1715 ** handler from inetd, for example. The argument is the name of the
1716 ** repository.
1717 **
1718 ** If REPOSITORY is a directory that contains one or more repositories,
1719 ** either directly in REPOSITORY itself, or in subdirectories, and
1720 ** with names of the form "*.fossil" then the a prefix of the URL pathname
1721 ** selects from among the various repositories. If the pathname does
1722 ** not select a valid repository and the --notfound option is available,
1723 ** then the server redirects (HTTP code 302) to the URL of --notfound.
1724 ** When REPOSITORY is a directory, the pathname must contain only
1725 ** alphanumerics, "_", "/", "-" and "." and no "-" may occur after a "/"
1726 ** and every "." must be surrounded on both sides by alphanumerics or else
1727 ** a 404 error is returned. Static content files in the directory are
1728 ** returned if they match comma-separate GLOB pattern specified by --files
1729 ** and do not match "*.fossil*" and have a well-known suffix.
1730 **
1731 ** The --host option can be used to specify the hostname for the server.
1732 ** The --https option indicates that the request came from HTTPS rather
1733 ** than HTTP. If --nossl is given, then SSL connections will not be available,
1734 ** thus also no redirecting from http: to https: will take place.
@@ -1723,19 +1741,34 @@
1741 ** --localauth enable automatic login for local connections
1742 ** --host NAME specify hostname of the server
1743 ** --https signal a request coming in via https
1744 ** --nossl signal that no SSL connections are available
1745 ** --notfound URL use URL as "HTTP 404, object not found" page.
1746 ** --files GLOB comma-separate glob patterns for static file to serve
1747 ** --baseurl URL base URL (useful with reverse proxies)
1748 **
1749 ** See also: cgi, server, winsrv
1750 */
1751 void cmd_http(void){
1752 const char *zIpAddr;
1753 const char *zNotFound;
1754 const char *zHost;
1755 const char *zAltBase;
1756 const char *zFileGlob;
1757
1758 /* The winhttp module passes the --files option as --files-urlenc with
1759 ** the argument being URL encoded, to avoid wildcard expansion in the
1760 ** shell. This option is for internal use and is undocumented.
1761 */
1762 zFileGlob = find_option("files-urlenc",0,1);
1763 if( zFileGlob ){
1764 char *z = mprintf("%s", zFileGlob);
1765 dehttpize(z);
1766 zFileGlob = z;
1767 }else{
1768 zFileGlob = find_option("files",0,1);
1769 }
1770 zNotFound = find_option("notfound", 0, 1);
1771 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1772 g.sslNotAvailable = find_option("nossl", 0, 0)!=0;
1773 zAltBase = find_option("baseurl", 0, 1);
1774 if( zAltBase ) set_base_url(zAltBase);
@@ -1757,11 +1790,11 @@
1790 zIpAddr = 0;
1791 }
1792 find_server_repository(0);
1793 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1794 cgi_handle_http_request(zIpAddr);
1795 process_one_web_page(zNotFound, glob_create(zFileGlob));
1796 }
1797
1798 /*
1799 ** Note that the following command is used by ssh:// processing.
1800 **
@@ -1780,11 +1813,11 @@
1813 g.httpOut = stdout;
1814 find_server_repository(0);
1815 g.cgiOutput = 1;
1816 g.fullHttpReply = 1;
1817 cgi_handle_http_request(0);
1818 process_one_web_page(0, 0);
1819 }
1820
1821 #if !defined(_WIN32)
1822 #if !defined(__DARWIN__) && !defined(__APPLE__) && !defined(__HAIKU__)
1823 /*
@@ -1825,20 +1858,23 @@
1858 **
1859 ** The "ui" command automatically starts a web browser after initializing
1860 ** the web server. The "ui" command also binds to 127.0.0.1 and so will
1861 ** only process HTTP traffic from the local machine.
1862 **
1863 ** The REPOSITORY can be a directory (aka folder) that contains one or
1864 ** more repositories with names ending in ".fossil". In this case, the
1865 ** a prefix of the URL pathname is used to search the directory for an
1866 ** appropriate repository. To thwart mischief, the pathname in the URL must
1867 ** contain only alphanumerics, "_", "/", "-", and ".", and no "-" may
1868 ** occur after "/", and every "." must be surrounded on both sides by
1869 ** alphanumerics. Any pathname that does not satisfy these constraints
1870 ** results in a 404 error. Files in REPOSITORY that match the comma-separated
1871 ** list of glob patterns given by --files and that have known suffixes
1872 ** such as ".txt" or ".html" or ".jpeg" and do not match the pattern
1873 ** "*.fossil*" will be served as static content. With the "ui" command,
1874 ** the REPOSITORY can only be a directory if the --notfound option is
1875 ** also present.
1876 **
1877 ** By default, the "ui" command provides full administrative access without
1878 ** having to log in. This can be disabled by setting turning off the
1879 ** "localauth" setting. Automatic login for the "server" command is available
1880 ** if the --localauth option is present and the "localauth" setting is off
@@ -1850,10 +1886,11 @@
1886 ** --localauth enable automatic login for requests from localhost
1887 ** -P|--port TCPPORT listen to request on port TCPPORT
1888 ** --th-trace trace TH1 execution (for debugging purposes)
1889 ** --baseurl URL Use URL as the base (useful for reverse proxies)
1890 ** --notfound URL Redirect
1891 ** --files GLOBLIST Comma-separated list of glob patterns for static files
1892 **
1893 ** See also: cgi, http, winsrv
1894 */
1895 void cmd_webserver(void){
1896 int iPort, mxPort; /* Range of TCP ports allowed */
@@ -1862,16 +1899,18 @@
1899 char *zBrowserCmd = 0; /* Command to launch the web browser */
1900 int isUiCmd; /* True if command is "ui", not "server' */
1901 const char *zNotFound; /* The --notfound option or NULL */
1902 int flags = 0; /* Server flags */
1903 const char *zAltBase; /* Argument to the --baseurl option */
1904 const char *zFileGlob; /* Static content must match this */
1905
1906 #if defined(_WIN32)
1907 const char *zStopperFile; /* Name of file used to terminate server */
1908 zStopperFile = find_option("stopper", 0, 1);
1909 #endif
1910
1911 zFileGlob = find_option("files", 0, 1);
1912 g.thTrace = find_option("th-trace", 0, 0)!=0;
1913 g.useLocalauth = find_option("localauth", 0, 0)!=0;
1914 if( g.thTrace ){
1915 blob_zero(&g.thLog);
1916 }
@@ -1927,21 +1966,21 @@
1966 }
1967 g.cgiOutput = 1;
1968 find_server_repository(isUiCmd && zNotFound==0);
1969 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1970 cgi_handle_http_request(0);
1971 process_one_web_page(zNotFound, glob_create(zFileGlob));
1972 #else
1973 /* Win32 implementation */
1974 if( isUiCmd ){
1975 zBrowser = db_get("web-browser", "start");
1976 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
1977 }
1978 db_close(1);
1979 if( win32_http_service(iPort, zNotFound, zFileGlob, flags) ){
1980 win32_http_server(iPort, mxPort, zBrowserCmd,
1981 zStopperFile, zNotFound, zFileGlob, flags);
1982 }
1983 #endif
1984 }
1985
1986 /*
1987
+12 -2
--- src/winhttp.c
+++ src/winhttp.c
@@ -138,10 +138,11 @@
138138
void win32_http_server(
139139
int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140140
const char *zBrowser, /* Command to launch browser. (Or NULL) */
141141
const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142142
const char *zNotFound, /* The --notfound option, or NULL */
143
+ const char *zFileGlob, /* The --fileglob option, or NULL */
143144
int flags /* One or more HTTP_SERVER_ flags */
144145
){
145146
WSADATA wd;
146147
SOCKET s = INVALID_SOCKET;
147148
SOCKADDR_IN addr;
@@ -153,10 +154,13 @@
153154
if( zStopper ) file_delete(zStopper);
154155
blob_zero(&options);
155156
if( zNotFound ){
156157
blob_appendf(&options, " --notfound %s", zNotFound);
157158
}
159
+ if( zFileGlob ){
160
+ blob_appendf(&options, " --files-urlenc %T", zFileGlob);
161
+ }
158162
if( g.useLocalauth ){
159163
blob_appendf(&options, " --localauth");
160164
}
161165
if( WSAStartup(MAKEWORD(1,1), &wd) ){
162166
fossil_fatal("unable to initialize winsock");
@@ -247,20 +251,21 @@
247251
*/
248252
typedef struct HttpService HttpService;
249253
struct HttpService {
250254
int port; /* Port on which the http server should run */
251255
const char *zNotFound; /* The --notfound option, or NULL */
256
+ const char *zFileGlob; /* The --files option, or NULL */
252257
int flags; /* One or more HTTP_SERVER_ flags */
253258
int isRunningAsService; /* Are we running as a service ? */
254259
const WCHAR *zServiceName;/* Name of the service */
255260
SOCKET s; /* Socket on which the http server listens */
256261
};
257262
258263
/*
259264
** Variables used for running as windows service.
260265
*/
261
-static HttpService hsData = {8080, NULL, 0, 0, NULL, INVALID_SOCKET};
266
+static HttpService hsData = {8080, NULL, NULL, 0, 0, NULL, INVALID_SOCKET};
262267
static SERVICE_STATUS ssStatus;
263268
static SERVICE_STATUS_HANDLE sshStatusHandle;
264269
265270
/*
266271
** Get message string of the last system error. Return a pointer to the
@@ -397,11 +402,12 @@
397402
ssStatus.dwServiceSpecificExitCode = 0;
398403
win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
399404
400405
/* Execute the http server */
401406
win32_http_server(hsData.port, hsData.port,
402
- NULL, NULL, hsData.zNotFound, hsData.flags);
407
+ NULL, NULL, hsData.zNotFound, hsData.zFileGlob,
408
+ hsData.flags);
403409
404410
/* Service has stopped now. */
405411
win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
406412
return;
407413
}
@@ -425,19 +431,21 @@
425431
** the service is stopped. In this case, the return value is zero.
426432
*/
427433
int win32_http_service(
428434
int nPort, /* TCP port number */
429435
const char *zNotFound, /* The --notfound option, or NULL */
436
+ const char *zFileGlob, /* The --files option, or NULL */
430437
int flags /* One or more HTTP_SERVER_ flags */
431438
){
432439
/* Define the service table. */
433440
SERVICE_TABLE_ENTRYW ServiceTable[] =
434441
{{L"", (LPSERVICE_MAIN_FUNCTIONW)win32_http_service_main}, {NULL, NULL}};
435442
436443
/* Initialize the HttpService structure. */
437444
hsData.port = nPort;
438445
hsData.zNotFound = zNotFound;
446
+ hsData.zFileGlob = zFileGlob;
439447
hsData.flags = flags;
440448
441449
/* Try to start the control dispatcher thread for the service. */
442450
if( !StartServiceCtrlDispatcherW(ServiceTable) ){
443451
if( GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ){
@@ -574,10 +582,11 @@
574582
const char *zStart = find_option("start", "S", 1);
575583
const char *zUsername = find_option("username", "U", 1);
576584
const char *zPassword = find_option("password", "W", 1);
577585
const char *zPort = find_option("port", "P", 1);
578586
const char *zNotFound = find_option("notfound", 0, 1);
587
+ const char *zFileGlob = find_option("files", 0, 1);
579588
const char *zLocalAuth = find_option("localauth", 0, 0);
580589
const char *zRepository = find_option("repository", "R", 1);
581590
Blob binPath;
582591
583592
verify_all_options();
@@ -617,10 +626,11 @@
617626
/* Build the fully-qualified path to the service binary file. */
618627
blob_zero(&binPath);
619628
blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
620629
if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
621630
if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
631
+ if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
622632
if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
623633
blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
624634
/* Create the service. */
625635
hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
626636
if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
627637
--- src/winhttp.c
+++ src/winhttp.c
@@ -138,10 +138,11 @@
138 void win32_http_server(
139 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140 const char *zBrowser, /* Command to launch browser. (Or NULL) */
141 const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142 const char *zNotFound, /* The --notfound option, or NULL */
 
143 int flags /* One or more HTTP_SERVER_ flags */
144 ){
145 WSADATA wd;
146 SOCKET s = INVALID_SOCKET;
147 SOCKADDR_IN addr;
@@ -153,10 +154,13 @@
153 if( zStopper ) file_delete(zStopper);
154 blob_zero(&options);
155 if( zNotFound ){
156 blob_appendf(&options, " --notfound %s", zNotFound);
157 }
 
 
 
158 if( g.useLocalauth ){
159 blob_appendf(&options, " --localauth");
160 }
161 if( WSAStartup(MAKEWORD(1,1), &wd) ){
162 fossil_fatal("unable to initialize winsock");
@@ -247,20 +251,21 @@
247 */
248 typedef struct HttpService HttpService;
249 struct HttpService {
250 int port; /* Port on which the http server should run */
251 const char *zNotFound; /* The --notfound option, or NULL */
 
252 int flags; /* One or more HTTP_SERVER_ flags */
253 int isRunningAsService; /* Are we running as a service ? */
254 const WCHAR *zServiceName;/* Name of the service */
255 SOCKET s; /* Socket on which the http server listens */
256 };
257
258 /*
259 ** Variables used for running as windows service.
260 */
261 static HttpService hsData = {8080, NULL, 0, 0, NULL, INVALID_SOCKET};
262 static SERVICE_STATUS ssStatus;
263 static SERVICE_STATUS_HANDLE sshStatusHandle;
264
265 /*
266 ** Get message string of the last system error. Return a pointer to the
@@ -397,11 +402,12 @@
397 ssStatus.dwServiceSpecificExitCode = 0;
398 win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
399
400 /* Execute the http server */
401 win32_http_server(hsData.port, hsData.port,
402 NULL, NULL, hsData.zNotFound, hsData.flags);
 
403
404 /* Service has stopped now. */
405 win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
406 return;
407 }
@@ -425,19 +431,21 @@
425 ** the service is stopped. In this case, the return value is zero.
426 */
427 int win32_http_service(
428 int nPort, /* TCP port number */
429 const char *zNotFound, /* The --notfound option, or NULL */
 
430 int flags /* One or more HTTP_SERVER_ flags */
431 ){
432 /* Define the service table. */
433 SERVICE_TABLE_ENTRYW ServiceTable[] =
434 {{L"", (LPSERVICE_MAIN_FUNCTIONW)win32_http_service_main}, {NULL, NULL}};
435
436 /* Initialize the HttpService structure. */
437 hsData.port = nPort;
438 hsData.zNotFound = zNotFound;
 
439 hsData.flags = flags;
440
441 /* Try to start the control dispatcher thread for the service. */
442 if( !StartServiceCtrlDispatcherW(ServiceTable) ){
443 if( GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ){
@@ -574,10 +582,11 @@
574 const char *zStart = find_option("start", "S", 1);
575 const char *zUsername = find_option("username", "U", 1);
576 const char *zPassword = find_option("password", "W", 1);
577 const char *zPort = find_option("port", "P", 1);
578 const char *zNotFound = find_option("notfound", 0, 1);
 
579 const char *zLocalAuth = find_option("localauth", 0, 0);
580 const char *zRepository = find_option("repository", "R", 1);
581 Blob binPath;
582
583 verify_all_options();
@@ -617,10 +626,11 @@
617 /* Build the fully-qualified path to the service binary file. */
618 blob_zero(&binPath);
619 blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
620 if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
621 if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
 
622 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
623 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
624 /* Create the service. */
625 hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
626 if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
627
--- src/winhttp.c
+++ src/winhttp.c
@@ -138,10 +138,11 @@
138 void win32_http_server(
139 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
140 const char *zBrowser, /* Command to launch browser. (Or NULL) */
141 const char *zStopper, /* Stop server when this file is exists (Or NULL) */
142 const char *zNotFound, /* The --notfound option, or NULL */
143 const char *zFileGlob, /* The --fileglob option, or NULL */
144 int flags /* One or more HTTP_SERVER_ flags */
145 ){
146 WSADATA wd;
147 SOCKET s = INVALID_SOCKET;
148 SOCKADDR_IN addr;
@@ -153,10 +154,13 @@
154 if( zStopper ) file_delete(zStopper);
155 blob_zero(&options);
156 if( zNotFound ){
157 blob_appendf(&options, " --notfound %s", zNotFound);
158 }
159 if( zFileGlob ){
160 blob_appendf(&options, " --files-urlenc %T", zFileGlob);
161 }
162 if( g.useLocalauth ){
163 blob_appendf(&options, " --localauth");
164 }
165 if( WSAStartup(MAKEWORD(1,1), &wd) ){
166 fossil_fatal("unable to initialize winsock");
@@ -247,20 +251,21 @@
251 */
252 typedef struct HttpService HttpService;
253 struct HttpService {
254 int port; /* Port on which the http server should run */
255 const char *zNotFound; /* The --notfound option, or NULL */
256 const char *zFileGlob; /* The --files option, or NULL */
257 int flags; /* One or more HTTP_SERVER_ flags */
258 int isRunningAsService; /* Are we running as a service ? */
259 const WCHAR *zServiceName;/* Name of the service */
260 SOCKET s; /* Socket on which the http server listens */
261 };
262
263 /*
264 ** Variables used for running as windows service.
265 */
266 static HttpService hsData = {8080, NULL, NULL, 0, 0, NULL, INVALID_SOCKET};
267 static SERVICE_STATUS ssStatus;
268 static SERVICE_STATUS_HANDLE sshStatusHandle;
269
270 /*
271 ** Get message string of the last system error. Return a pointer to the
@@ -397,11 +402,12 @@
402 ssStatus.dwServiceSpecificExitCode = 0;
403 win32_report_service_status(SERVICE_START_PENDING, NO_ERROR, 3000);
404
405 /* Execute the http server */
406 win32_http_server(hsData.port, hsData.port,
407 NULL, NULL, hsData.zNotFound, hsData.zFileGlob,
408 hsData.flags);
409
410 /* Service has stopped now. */
411 win32_report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
412 return;
413 }
@@ -425,19 +431,21 @@
431 ** the service is stopped. In this case, the return value is zero.
432 */
433 int win32_http_service(
434 int nPort, /* TCP port number */
435 const char *zNotFound, /* The --notfound option, or NULL */
436 const char *zFileGlob, /* The --files option, or NULL */
437 int flags /* One or more HTTP_SERVER_ flags */
438 ){
439 /* Define the service table. */
440 SERVICE_TABLE_ENTRYW ServiceTable[] =
441 {{L"", (LPSERVICE_MAIN_FUNCTIONW)win32_http_service_main}, {NULL, NULL}};
442
443 /* Initialize the HttpService structure. */
444 hsData.port = nPort;
445 hsData.zNotFound = zNotFound;
446 hsData.zFileGlob = zFileGlob;
447 hsData.flags = flags;
448
449 /* Try to start the control dispatcher thread for the service. */
450 if( !StartServiceCtrlDispatcherW(ServiceTable) ){
451 if( GetLastError()==ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ){
@@ -574,10 +582,11 @@
582 const char *zStart = find_option("start", "S", 1);
583 const char *zUsername = find_option("username", "U", 1);
584 const char *zPassword = find_option("password", "W", 1);
585 const char *zPort = find_option("port", "P", 1);
586 const char *zNotFound = find_option("notfound", 0, 1);
587 const char *zFileGlob = find_option("files", 0, 1);
588 const char *zLocalAuth = find_option("localauth", 0, 0);
589 const char *zRepository = find_option("repository", "R", 1);
590 Blob binPath;
591
592 verify_all_options();
@@ -617,10 +626,11 @@
626 /* Build the fully-qualified path to the service binary file. */
627 blob_zero(&binPath);
628 blob_appendf(&binPath, "\"%s\" server", g.nameOfExe);
629 if( zPort ) blob_appendf(&binPath, " --port %s", zPort);
630 if( zNotFound ) blob_appendf(&binPath, " --notfound \"%s\"", zNotFound);
631 if( zFileGlob ) blob_appendf(&binPath, " --files-urlenc %T", zFileGlob);
632 if( zLocalAuth ) blob_append(&binPath, " --localauth", -1);
633 blob_appendf(&binPath, " \"%s\"", g.zRepositoryName);
634 /* Create the service. */
635 hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
636 if( !hScm ) fossil_fatal(zErrFmt, zSvcName, win32_get_last_errmsg());
637

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button