Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the --notfound option to the "http" and "server" command. For CGI, add configuration lines "directory:" and "notfound:". |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
49cffc01871f7cb5fdd26967818b4a8f |
User & Date: | drh 2010-02-03 14:36:27 |
References
2010-02-04
| ||
06:09 | • Deferred ticket [6b498a79]: Cyrillic symbols does not display correctly plus 2 other changes ... (artifact: 7d118f87 user: ron) | |
Context
2010-02-05
| ||
16:22 | The RSS feed is restricted to the permissions granted to user 'nobody'. Ticket [09ba8cea6f] ... (check-in: 78a6270f user: drh tags: trunk) | |
2010-02-03
| ||
14:36 | Add the --notfound option to the "http" and "server" command. For CGI, add configuration lines "directory:" and "notfound:". ... (check-in: 49cffc01 user: drh tags: trunk) | |
2010-02-01
| ||
15:07 | Make the new multi-repository fossil server feature work with the "clone" command. ... (check-in: a918bdf5 user: drh tags: trunk) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 | /* ** Send an HTTP redirect back to the designated Index Page. */ void fossil_redirect_home(void){ cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index")); } /* ** Preconditions: ** ** * Environment variables are set up according to the CGI standard. ** ** If the repository is known, it has already been opened. If unknown, ** then g.zRepositoryName holds the directory that contains the repository ** and the actual repository is taken from the first element of PATH_INFO. ** ** Process the webpage specified by the PATH_INFO or REQUEST_URI ** environment variable. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 | /* ** Send an HTTP redirect back to the designated Index Page. */ void fossil_redirect_home(void){ cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index")); } /* ** If running as root, chroot to the directory containing the ** repository zRepo and then drop root privileges. Return the ** new repository name. ** ** zRepo might be a directory itself. In that case chroot into ** the directory zRepo. ** ** Assume the user-id and group-id of the repository, or if zRepo ** is a directory, of that directory. */ static char *enter_chroot_jail(char *zRepo){ #if !defined(__MINGW32__) if( getuid()==0 ){ int i; struct stat sStat; Blob dir; char *zDir; file_canonical_name(zRepo, &dir); zDir = blob_str(&dir); if( file_isdir(zDir)==1 ){ chdir(zDir); chroot(zDir); zRepo = "/"; }else{ for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){} if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo); zDir[i] = 0; chdir(zDir); chroot(zDir); zDir[i] = '/'; zRepo = &zDir[i]; } if( stat(zRepo, &sStat)!=0 ){ fossil_fatal("cannot stat() repository: %s", zRepo); } setgid(sStat.st_gid); setuid(sStat.st_uid); } #endif return zRepo; } /* ** Preconditions: ** ** * Environment variables are set up according to the CGI standard. ** ** If the repository is known, it has already been opened. If unknown, ** then g.zRepositoryName holds the directory that contains the repository ** and the actual repository is taken from the first element of PATH_INFO. ** ** Process the webpage specified by the PATH_INFO or REQUEST_URI ** environment variable. */ static void process_one_web_page(const char *zNotFound){ const char *zPathInfo; char *zPath = NULL; int idx; int i; /* If the repository has not been opened already, then find the ** repository based on the first element of PATH_INFO and open it. |
︙ | ︙ | |||
606 607 608 609 610 611 612 | ** characters other than alphanumerics, "-", and "_". */ for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){ if( !isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_'; } if( file_size(zRepo)<1024 ){ | > > > | | | > | 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 | ** characters other than alphanumerics, "-", and "_". */ for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){ if( !isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_'; } if( file_size(zRepo)<1024 ){ if( zNotFound ){ cgi_redirect(zNotFound); }else{ @ <h1>Not Found</h1> 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); |
︙ | ︙ | |||
701 702 703 704 705 706 707 708 709 710 711 712 713 714 | ** ** The second line defines the name of the repository. After locating ** the repository, fossil will generate a webpage on stdout based on ** the values of standard CGI environment variables. */ void cmd_cgi(void){ const char *zFile; Blob config, line, key, value; if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){ zFile = g.argv[2]; }else{ zFile = g.argv[1]; } g.httpOut = stdout; | > | 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 | ** ** The second line defines the name of the repository. After locating ** the repository, fossil will generate a webpage on stdout based on ** the values of standard CGI environment variables. */ void cmd_cgi(void){ const char *zFile; const char *zNotFound = 0; Blob config, line, key, value; if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){ zFile = g.argv[2]; }else{ zFile = g.argv[1]; } g.httpOut = stdout; |
︙ | ︙ | |||
738 739 740 741 742 743 744 | cgi_setenv("HOME", blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){ db_open_repository(blob_str(&value)); blob_reset(&value); | > > > > > | > > > > | > > | | | 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 | cgi_setenv("HOME", blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){ db_open_repository(blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){ db_close(); g.zRepositoryName = mprintf("%s", blob_str(&value)); blob_reset(&value); continue; } if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){ zNotFound = mprintf("%s", blob_str(&value)); blob_reset(&value); continue; } } blob_reset(&config); if( g.db==0 && g.zRepositoryName==0 ){ cgi_panic("Unable to find or open the project repository"); } cgi_init(); process_one_web_page(zNotFound); } /* ** 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 |
︙ | ︙ | |||
787 788 789 790 791 792 793 | ** ** fossil http REPOSITORY INFILE OUTFILE IPADDR ** ** The argv==6 form is used by the win32 server only. ** ** COMMAND: http ** | | | > > > > < < < < < < < < < < < < < < < < < < < > | | 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 | ** ** fossil http REPOSITORY INFILE OUTFILE IPADDR ** ** The argv==6 form is used by the win32 server only. ** ** COMMAND: http ** ** Usage: %fossil http REPOSITORY [--notfound URL] ** ** 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. If the pathname does ** not select a valid repository and the --notfound option is available, ** then the server redirects (HTTP code 302) to the URL of --notfound. */ void cmd_http(void){ const char *zIpAddr; const char *zNotFound; zNotFound = find_option("notfound", 0, 1); if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ cgi_panic("no repository specified"); } g.cgiPanic = 1; g.fullHttpReply = 1; if( g.argc==6 ){ g.httpIn = fopen(g.argv[3], "rb"); g.httpOut = fopen(g.argv[4], "wb"); zIpAddr = g.argv[5]; }else{ g.httpIn = stdin; g.httpOut = stdout; zIpAddr = 0; } find_server_repository(0); g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); cgi_handle_http_request(zIpAddr); process_one_web_page(zNotFound); } /* ** COMMAND: test-http ** Works like the http command but gives setup permission to all users. */ void cmd_test_http(void){ |
︙ | ︙ | |||
894 895 896 897 898 899 900 | ** ** 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){ | | | | | > > | 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 | ** ** 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; /* Range of TCP ports allowed */ const char *zPort; /* Value of the --port option */ char *zBrowser; /* Name of web browser program */ char *zBrowserCmd = 0; /* Command to launch the web browser */ int isUiCmd; /* True if command is "ui", not "server' */ const char *zNotFound; /* The --notfound option or NULL */ #ifdef __MINGW32__ const char *zStopperFile; /* Name of file used to terminate server */ zStopperFile = find_option("stopper", 0, 1); #endif g.thTrace = find_option("th-trace", 0, 0)!=0; if( g.thTrace ){ blob_zero(&g.thLog); } zPort = find_option("port", "P", 1); zNotFound = find_option("notfound", 0, 1); if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); isUiCmd = g.argv[1][0]=='u'; find_server_repository(isUiCmd); if( zPort ){ iPort = mxPort = atoi(zPort); }else{ iPort = db_get_int("http-port", 8080); |
︙ | ︙ | |||
951 952 953 954 955 956 957 958 | g.httpIn = stdin; g.httpOut = stdout; if( g.fHttpTrace || g.fSqlTrace ){ fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); } g.cgiPanic = 1; find_server_repository(isUiCmd); cgi_handle_http_request(0); | > | | | 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 | g.httpIn = stdin; g.httpOut = stdout; if( g.fHttpTrace || g.fSqlTrace ){ fprintf(stderr, "====== SERVER pid %d =======\n", getpid()); } g.cgiPanic = 1; find_server_repository(isUiCmd); g.zRepositoryName = enter_chroot_jail(g.zRepositoryName); cgi_handle_http_request(0); process_one_web_page(zNotFound); #else /* Win32 implementation */ 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, zNotFound); #endif } |
Changes to src/winhttp.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 41 42 43 44 45 46 47 | ** HTTP request. */ typedef struct HttpRequest HttpRequest; struct HttpRequest { int id; /* ID counter */ SOCKET s; /* Socket on which to receive data */ SOCKADDR_IN addr; /* Address from which data is coming */ }; /* ** Prefix for a temporary file. */ static char *zTempPrefix; | > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | ** HTTP request. */ typedef struct HttpRequest HttpRequest; struct HttpRequest { int id; /* ID counter */ SOCKET s; /* Socket on which to receive data */ SOCKADDR_IN addr; /* Address from which data is coming */ const char *zNotFound; /* --notfound option, or an empty string */ }; /* ** Prefix for a temporary file. */ static char *zTempPrefix; |
︙ | ︙ | |||
107 108 109 110 111 112 113 | }else{ break; } wanted -= got; } fclose(out); out = 0; | | | | 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | }else{ break; } wanted -= got; } fclose(out); out = 0; sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s%s", g.argv[0], g.zRepositoryName, zRequestFName, zReplyFName, inet_ntoa(p->addr.sin_addr), p->zNotFound ); portable_system(zCmd); in = fopen(zReplyFName, "rb"); if( in ){ while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ send(p->s, zHdr, got, 0); } |
︙ | ︙ | |||
135 136 137 138 139 140 141 | /* ** Start a listening socket and process incoming HTTP requests on ** that socket. */ void win32_http_server( int mnPort, int mxPort, /* Range of allowed TCP port numbers */ char *zBrowser, /* Command to launch browser. (Or NULL) */ | | > > > > > > > | 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | /* ** Start a listening socket and process incoming HTTP requests on ** that socket. */ void win32_http_server( int mnPort, int mxPort, /* Range of allowed TCP port numbers */ char *zBrowser, /* Command to launch browser. (Or NULL) */ char *zStopper, /* Stop server when this file is exists (Or NULL) */ char *zNotFound /* The --notfound option, or NULL */ ){ WSADATA wd; SOCKET s = INVALID_SOCKET; SOCKADDR_IN addr; int idCnt = 0; int iPort = mnPort; char *zNotFoundOption; if( zStopper ) unlink(zStopper); if( zNotFound ){ zNotFoundOption = mprintf(" --notfound %s", zNotFound); }else{ zNotFoundOption = ""; } if( WSAStartup(MAKEWORD(1,1), &wd) ){ fossil_fatal("unable to initialize winsock"); } while( iPort<=mxPort ){ s = socket(AF_INET, SOCK_STREAM, 0); if( s==INVALID_SOCKET ){ fossil_fatal("unable to create a socket"); |
︙ | ︙ | |||
204 205 206 207 208 209 210 211 212 213 214 215 216 217 | p = malloc( sizeof(*p) ); if( p==0 ){ fossil_fatal("out of memory"); } p->id = ++idCnt; p->s = client; p->addr = client_addr; _beginthread(win32_process_one_http_request, 0, (void*)p); } closesocket(s); WSACleanup(); } #endif /* __MINGW32__ -- This code is for win32 only */ | > | 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | p = malloc( sizeof(*p) ); if( p==0 ){ fossil_fatal("out of memory"); } p->id = ++idCnt; p->s = client; p->addr = client_addr; p->zNotFound = zNotFoundOption; _beginthread(win32_process_one_http_request, 0, (void*)p); } closesocket(s); WSACleanup(); } #endif /* __MINGW32__ -- This code is for win32 only */ |
Changes to www/index.wiki.
︙ | ︙ | |||
54 55 56 57 58 59 60 | history and status information on that project. 3. <b>Autosync</b> - Fossil supports [./concepts.wiki#workflow | "autosync" mode] which helps to keep projects moving forward by reducing the amount of needless [./branching.wiki | forking and merging] often | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | history and status information on that project. 3. <b>Autosync</b> - Fossil supports [./concepts.wiki#workflow | "autosync" mode] which helps to keep projects moving forward by reducing the amount of needless [./branching.wiki | forking and merging] often associated with distributed projects. 4. <b>Self-Contained</b> - Fossil is a single stand-alone executable that contains everything needed to do configuration management. Installation is trivial: simply download a <a href="http://www.fossil-scm.org/download.html">precompiled binary</a> for Linux, Mac, or Windows and put it on your $PATH. |
︙ | ︙ |