Index: src/file.c ================================================================== --- src/file.c +++ src/file.c @@ -101,11 +101,11 @@ int file_isdir(const char *zFilename){ int rc; if( zFilename ){ char *zFN = mprintf("%s", zFilename); - file_simplify_name(zFN, strlen(zFN)); + file_simplify_name(zFN, -1); rc = getStat(zFN); free(zFN); }else{ rc = getStat(0); } @@ -229,10 +229,11 @@ ** ** Changes are made in-place. Return the new name length. */ int file_simplify_name(char *z, int n){ int i, j; + if( n<0 ) n = strlen(z); #ifdef __MINGW32__ for(i=0; iNot Found + cgi_set_status(404, "not found"); + cgi_reply(); + return; + } + zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo); + cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]); + zPathInfo += i; + cgi_replace_parameter("SCRIPT_NAME", zNewScript); + db_open_repository(zRepo); + } /* Find the page that the user has requested, construct and deliver that ** page. */ set_base_url(); - zPathInfo = P("PATH_INFO"); if( zPathInfo==0 || zPathInfo[0]==0 || (zPathInfo[0]=='/' && zPathInfo[1]==0) ){ fossil_redirect_home(); }else{ zPath = mprintf("%s", zPathInfo); @@ -707,10 +743,39 @@ cgi_panic("Unable to find or open the project repository"); } cgi_init(); process_one_web_page(); } + +/* +** If g.argv[2] exists then it is either the name of a repository +** that will be used by a server, or else it is a directory that +** contains multiple repositories that can be served. If g.argv[2] +** is a directory, the repositories it contains must be named +** "*.fossil". If g.argv[2] does not exists, then we must be within +** a check-out and the repository to be served is the repository of +** that check-out. +** +** Open the respository to be served if it is known. If g.argv[2] is +** a directory full of repositories, then set g.zRepositoryName to +** the name of that directory and the specific repository will be +** opened later by process_one_web_page() based on the content of +** the PATH_INFO variable. +** +** If disallowDir is set, then the directory full of repositories method +** is disallowed. +*/ +static void find_server_repository(int disallowDir){ + if( g.argc<3 ){ + db_must_be_within_tree(); + }else if( !disallowDir && file_isdir(g.argv[2])==1 ){ + g.zRepositoryName = mprintf("%s", g.argv[2]); + file_simplify_name(g.zRepositoryName, -1); + }else{ + db_open_repository(g.argv[2]); + } +} /* ** undocumented format: ** ** fossil http REPOSITORY INFILE OUTFILE IPADDR @@ -723,10 +788,14 @@ ** ** Handle a single HTTP request appearing on stdin. The resulting webpage ** is delivered on stdout. This method is used to launch an HTTP request ** handler from inetd, for example. The argument is the name of the ** repository. +** +** If REPOSITORY is a directory that contains one or more respositories +** with names of the form "*.fossil" then the first element of the URL +** pathname selects among the various repositories. */ void cmd_http(void){ const char *zIpAddr; if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ cgi_panic("no repository specified"); @@ -759,15 +828,11 @@ }else{ g.httpIn = stdin; g.httpOut = stdout; zIpAddr = 0; } - if( g.argc>=3 ){ - db_open_repository(g.argv[2]); - }else{ - db_must_be_within_tree(); - } + find_server_repository(0); cgi_handle_http_request(zIpAddr); process_one_web_page(); } /* @@ -817,16 +882,22 @@ ** The repository argument may be omitted if the working directory is ** within an open checkout. ** ** The "ui" command automatically starts a web browser after initializing ** the web server. +** +** In the "server" command, the REPOSITORY can be a directory (aka folder) +** that contains one or more respositories with names ending in ".fossil". +** In that case, the first element of the URL is used to select among the +** various repositories. */ void cmd_webserver(void){ int iPort, mxPort; const char *zPort; char *zBrowser; char *zBrowserCmd = 0; + int isUiCmd; /* True if command is "ui", not "server' */ #ifdef __MINGW32__ const char *zStopperFile; /* Name of file used to terminate server */ zStopperFile = find_option("stopper", 0, 1); #endif @@ -835,24 +906,21 @@ if( g.thTrace ){ blob_zero(&g.thLog); } zPort = find_option("port", "P", 1); if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); - if( g.argc==2 ){ - db_must_be_within_tree(); - }else{ - db_open_repository(g.argv[2]); - } + isUiCmd = g.argv[1][0]=='u'; + find_server_repository(isUiCmd); if( zPort ){ iPort = mxPort = atoi(zPort); }else{ iPort = db_get_int("http-port", 8080); mxPort = iPort+100; } #ifndef __MINGW32__ /* Unix implementation */ - if( g.argv[1][0]=='u' ){ + if( isUiCmd ){ #if !defined(__DARWIN__) && !defined(__APPLE__) zBrowser = db_get("web-browser", 0); if( zBrowser==0 ){ static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" }; int i; @@ -877,22 +945,18 @@ g.httpOut = stdout; if( g.fHttpTrace || g.fSqlTrace ){ fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); } g.cgiPanic = 1; - if( g.argc==2 ){ - db_must_be_within_tree(); - }else{ - db_open_repository(g.argv[2]); - } + find_server_repository(isUiCmd); cgi_handle_http_request(0); process_one_web_page(); #else /* Win32 implementation */ - if( g.argv[1][0]=='u' ){ + if( isUiCmd ){ zBrowser = db_get("web-browser", "start"); zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser); } db_close(); win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile); #endif }