Fossil SCM

Add the --notfound option to the "http" and "server" command. For CGI, add configuration lines "directory:" and "notfound:".

drh 2010-02-03 14:36 trunk
Commit 49cffc01871f7cb5fdd26967818b4a8fcd6a253d
3 files changed +85 -36 +12 -3 +1 -1
+85 -36
--- src/main.c
+++ src/main.c
@@ -567,10 +567,54 @@
567567
** Send an HTTP redirect back to the designated Index Page.
568568
*/
569569
void fossil_redirect_home(void){
570570
cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index"));
571571
}
572
+
573
+/*
574
+** If running as root, chroot to the directory containing the
575
+** repository zRepo and then drop root privileges. Return the
576
+** new repository name.
577
+**
578
+** zRepo might be a directory itself. In that case chroot into
579
+** the directory zRepo.
580
+**
581
+** Assume the user-id and group-id of the repository, or if zRepo
582
+** is a directory, of that directory.
583
+*/
584
+static char *enter_chroot_jail(char *zRepo){
585
+#if !defined(__MINGW32__)
586
+ if( getuid()==0 ){
587
+ int i;
588
+ struct stat sStat;
589
+ Blob dir;
590
+ char *zDir;
591
+
592
+ file_canonical_name(zRepo, &dir);
593
+ zDir = blob_str(&dir);
594
+ if( file_isdir(zDir)==1 ){
595
+ chdir(zDir);
596
+ chroot(zDir);
597
+ zRepo = "/";
598
+ }else{
599
+ for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
600
+ if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
601
+ zDir[i] = 0;
602
+ chdir(zDir);
603
+ chroot(zDir);
604
+ zDir[i] = '/';
605
+ zRepo = &zDir[i];
606
+ }
607
+ if( stat(zRepo, &sStat)!=0 ){
608
+ fossil_fatal("cannot stat() repository: %s", zRepo);
609
+ }
610
+ setgid(sStat.st_gid);
611
+ setuid(sStat.st_uid);
612
+ }
613
+#endif
614
+ return zRepo;
615
+}
572616
573617
/*
574618
** Preconditions:
575619
**
576620
** * Environment variables are set up according to the CGI standard.
@@ -580,11 +624,11 @@
580624
** and the actual repository is taken from the first element of PATH_INFO.
581625
**
582626
** Process the webpage specified by the PATH_INFO or REQUEST_URI
583627
** environment variable.
584628
*/
585
-static void process_one_web_page(void){
629
+static void process_one_web_page(const char *zNotFound){
586630
const char *zPathInfo;
587631
char *zPath = NULL;
588632
int idx;
589633
int i;
590634
@@ -608,13 +652,17 @@
608652
for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
609653
if( !isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_';
610654
}
611655
612656
if( file_size(zRepo)<1024 ){
613
- @ <h1>Not Found</h1>
614
- cgi_set_status(404, "not found");
615
- cgi_reply();
657
+ if( zNotFound ){
658
+ cgi_redirect(zNotFound);
659
+ }else{
660
+ @ <h1>Not Found</h1>
661
+ cgi_set_status(404, "not found");
662
+ cgi_reply();
663
+ }
616664
return;
617665
}
618666
zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
619667
cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
620668
zPathInfo += i;
@@ -703,10 +751,11 @@
703751
** the repository, fossil will generate a webpage on stdout based on
704752
** the values of standard CGI environment variables.
705753
*/
706754
void cmd_cgi(void){
707755
const char *zFile;
756
+ const char *zNotFound = 0;
708757
Blob config, line, key, value;
709758
if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){
710759
zFile = g.argv[2];
711760
}else{
712761
zFile = g.argv[1];
@@ -740,19 +789,30 @@
740789
continue;
741790
}
742791
if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){
743792
db_open_repository(blob_str(&value));
744793
blob_reset(&value);
745
- blob_reset(&config);
746
- break;
794
+ continue;
795
+ }
796
+ if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
797
+ db_close();
798
+ g.zRepositoryName = mprintf("%s", blob_str(&value));
799
+ blob_reset(&value);
800
+ continue;
801
+ }
802
+ if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
803
+ zNotFound = mprintf("%s", blob_str(&value));
804
+ blob_reset(&value);
805
+ continue;
747806
}
748807
}
749
- if( g.db==0 ){
808
+ blob_reset(&config);
809
+ if( g.db==0 && g.zRepositoryName==0 ){
750810
cgi_panic("Unable to find or open the project repository");
751811
}
752812
cgi_init();
753
- process_one_web_page();
813
+ process_one_web_page(zNotFound);
754814
}
755815
756816
/*
757817
** If g.argv[2] exists then it is either the name of a repository
758818
** that will be used by a server, or else it is a directory that
@@ -789,45 +849,30 @@
789849
**
790850
** The argv==6 form is used by the win32 server only.
791851
**
792852
** COMMAND: http
793853
**
794
-** Usage: %fossil http REPOSITORY
854
+** Usage: %fossil http REPOSITORY [--notfound URL]
795855
**
796856
** Handle a single HTTP request appearing on stdin. The resulting webpage
797857
** is delivered on stdout. This method is used to launch an HTTP request
798858
** handler from inetd, for example. The argument is the name of the
799859
** repository.
800860
**
801861
** If REPOSITORY is a directory that contains one or more respositories
802862
** with names of the form "*.fossil" then the first element of the URL
803
-** pathname selects among the various repositories.
863
+** pathname selects among the various repositories. If the pathname does
864
+** not select a valid repository and the --notfound option is available,
865
+** then the server redirects (HTTP code 302) to the URL of --notfound.
804866
*/
805867
void cmd_http(void){
806868
const char *zIpAddr;
869
+ const char *zNotFound;
870
+ zNotFound = find_option("notfound", 0, 1);
807871
if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
808872
cgi_panic("no repository specified");
809873
}
810
-#if !defined(__MINGW32__)
811
- if( g.argc==3 && getuid()==0 ){
812
- int i;
813
- char *zRepo = g.argv[2];
814
- struct stat sStat;
815
- for(i=strlen(zRepo)-1; i>0 && zRepo[i]!='/'; i--){}
816
- if( zRepo[i]=='/' ){
817
- zRepo[i] = 0;
818
- chdir(g.argv[2]);
819
- chroot(g.argv[2]);
820
- g.argv[2] = &zRepo[i+1];
821
- }
822
- if( stat(g.argv[2], &sStat)!=0 ){
823
- fossil_fatal("cannot stat() repository: %s", g.argv[2]);
824
- }
825
- setgid(sStat.st_gid);
826
- setuid(sStat.st_uid);
827
- }
828
-#endif
829874
g.cgiPanic = 1;
830875
g.fullHttpReply = 1;
831876
if( g.argc==6 ){
832877
g.httpIn = fopen(g.argv[3], "rb");
833878
g.httpOut = fopen(g.argv[4], "wb");
@@ -836,12 +881,13 @@
836881
g.httpIn = stdin;
837882
g.httpOut = stdout;
838883
zIpAddr = 0;
839884
}
840885
find_server_repository(0);
886
+ g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
841887
cgi_handle_http_request(zIpAddr);
842
- process_one_web_page();
888
+ process_one_web_page(zNotFound);
843889
}
844890
845891
/*
846892
** COMMAND: test-http
847893
** Works like the http command but gives setup permission to all users.
@@ -896,15 +942,16 @@
896942
** that contains one or more respositories with names ending in ".fossil".
897943
** In that case, the first element of the URL is used to select among the
898944
** various repositories.
899945
*/
900946
void cmd_webserver(void){
901
- int iPort, mxPort;
902
- const char *zPort;
903
- char *zBrowser;
904
- char *zBrowserCmd = 0;
947
+ int iPort, mxPort; /* Range of TCP ports allowed */
948
+ const char *zPort; /* Value of the --port option */
949
+ char *zBrowser; /* Name of web browser program */
950
+ char *zBrowserCmd = 0; /* Command to launch the web browser */
905951
int isUiCmd; /* True if command is "ui", not "server' */
952
+ const char *zNotFound; /* The --notfound option or NULL */
906953
907954
#ifdef __MINGW32__
908955
const char *zStopperFile; /* Name of file used to terminate server */
909956
zStopperFile = find_option("stopper", 0, 1);
910957
#endif
@@ -912,10 +959,11 @@
912959
g.thTrace = find_option("th-trace", 0, 0)!=0;
913960
if( g.thTrace ){
914961
blob_zero(&g.thLog);
915962
}
916963
zPort = find_option("port", "P", 1);
964
+ zNotFound = find_option("notfound", 0, 1);
917965
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
918966
isUiCmd = g.argv[1][0]=='u';
919967
find_server_repository(isUiCmd);
920968
if( zPort ){
921969
iPort = mxPort = atoi(zPort);
@@ -953,17 +1001,18 @@
9531001
if( g.fHttpTrace || g.fSqlTrace ){
9541002
fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
9551003
}
9561004
g.cgiPanic = 1;
9571005
find_server_repository(isUiCmd);
1006
+ g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
9581007
cgi_handle_http_request(0);
959
- process_one_web_page();
1008
+ process_one_web_page(zNotFound);
9601009
#else
9611010
/* Win32 implementation */
9621011
if( isUiCmd ){
9631012
zBrowser = db_get("web-browser", "start");
9641013
zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
9651014
}
9661015
db_close();
967
- win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile);
1016
+ win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound);
9681017
#endif
9691018
}
9701019
--- src/main.c
+++ src/main.c
@@ -567,10 +567,54 @@
567 ** Send an HTTP redirect back to the designated Index Page.
568 */
569 void fossil_redirect_home(void){
570 cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index"));
571 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
572
573 /*
574 ** Preconditions:
575 **
576 ** * Environment variables are set up according to the CGI standard.
@@ -580,11 +624,11 @@
580 ** and the actual repository is taken from the first element of PATH_INFO.
581 **
582 ** Process the webpage specified by the PATH_INFO or REQUEST_URI
583 ** environment variable.
584 */
585 static void process_one_web_page(void){
586 const char *zPathInfo;
587 char *zPath = NULL;
588 int idx;
589 int i;
590
@@ -608,13 +652,17 @@
608 for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
609 if( !isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_';
610 }
611
612 if( file_size(zRepo)<1024 ){
613 @ <h1>Not Found</h1>
614 cgi_set_status(404, "not found");
615 cgi_reply();
 
 
 
 
616 return;
617 }
618 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
619 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
620 zPathInfo += i;
@@ -703,10 +751,11 @@
703 ** the repository, fossil will generate a webpage on stdout based on
704 ** the values of standard CGI environment variables.
705 */
706 void cmd_cgi(void){
707 const char *zFile;
 
708 Blob config, line, key, value;
709 if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){
710 zFile = g.argv[2];
711 }else{
712 zFile = g.argv[1];
@@ -740,19 +789,30 @@
740 continue;
741 }
742 if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){
743 db_open_repository(blob_str(&value));
744 blob_reset(&value);
745 blob_reset(&config);
746 break;
 
 
 
 
 
 
 
 
 
 
747 }
748 }
749 if( g.db==0 ){
 
750 cgi_panic("Unable to find or open the project repository");
751 }
752 cgi_init();
753 process_one_web_page();
754 }
755
756 /*
757 ** If g.argv[2] exists then it is either the name of a repository
758 ** that will be used by a server, or else it is a directory that
@@ -789,45 +849,30 @@
789 **
790 ** The argv==6 form is used by the win32 server only.
791 **
792 ** COMMAND: http
793 **
794 ** Usage: %fossil http REPOSITORY
795 **
796 ** Handle a single HTTP request appearing on stdin. The resulting webpage
797 ** is delivered on stdout. This method is used to launch an HTTP request
798 ** handler from inetd, for example. The argument is the name of the
799 ** repository.
800 **
801 ** If REPOSITORY is a directory that contains one or more respositories
802 ** with names of the form "*.fossil" then the first element of the URL
803 ** pathname selects among the various repositories.
 
 
804 */
805 void cmd_http(void){
806 const char *zIpAddr;
 
 
807 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
808 cgi_panic("no repository specified");
809 }
810 #if !defined(__MINGW32__)
811 if( g.argc==3 && getuid()==0 ){
812 int i;
813 char *zRepo = g.argv[2];
814 struct stat sStat;
815 for(i=strlen(zRepo)-1; i>0 && zRepo[i]!='/'; i--){}
816 if( zRepo[i]=='/' ){
817 zRepo[i] = 0;
818 chdir(g.argv[2]);
819 chroot(g.argv[2]);
820 g.argv[2] = &zRepo[i+1];
821 }
822 if( stat(g.argv[2], &sStat)!=0 ){
823 fossil_fatal("cannot stat() repository: %s", g.argv[2]);
824 }
825 setgid(sStat.st_gid);
826 setuid(sStat.st_uid);
827 }
828 #endif
829 g.cgiPanic = 1;
830 g.fullHttpReply = 1;
831 if( g.argc==6 ){
832 g.httpIn = fopen(g.argv[3], "rb");
833 g.httpOut = fopen(g.argv[4], "wb");
@@ -836,12 +881,13 @@
836 g.httpIn = stdin;
837 g.httpOut = stdout;
838 zIpAddr = 0;
839 }
840 find_server_repository(0);
 
841 cgi_handle_http_request(zIpAddr);
842 process_one_web_page();
843 }
844
845 /*
846 ** COMMAND: test-http
847 ** Works like the http command but gives setup permission to all users.
@@ -896,15 +942,16 @@
896 ** that contains one or more respositories with names ending in ".fossil".
897 ** In that case, the first element of the URL is used to select among the
898 ** various repositories.
899 */
900 void cmd_webserver(void){
901 int iPort, mxPort;
902 const char *zPort;
903 char *zBrowser;
904 char *zBrowserCmd = 0;
905 int isUiCmd; /* True if command is "ui", not "server' */
 
906
907 #ifdef __MINGW32__
908 const char *zStopperFile; /* Name of file used to terminate server */
909 zStopperFile = find_option("stopper", 0, 1);
910 #endif
@@ -912,10 +959,11 @@
912 g.thTrace = find_option("th-trace", 0, 0)!=0;
913 if( g.thTrace ){
914 blob_zero(&g.thLog);
915 }
916 zPort = find_option("port", "P", 1);
 
917 if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
918 isUiCmd = g.argv[1][0]=='u';
919 find_server_repository(isUiCmd);
920 if( zPort ){
921 iPort = mxPort = atoi(zPort);
@@ -953,17 +1001,18 @@
953 if( g.fHttpTrace || g.fSqlTrace ){
954 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
955 }
956 g.cgiPanic = 1;
957 find_server_repository(isUiCmd);
 
958 cgi_handle_http_request(0);
959 process_one_web_page();
960 #else
961 /* Win32 implementation */
962 if( isUiCmd ){
963 zBrowser = db_get("web-browser", "start");
964 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
965 }
966 db_close();
967 win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile);
968 #endif
969 }
970
--- src/main.c
+++ src/main.c
@@ -567,10 +567,54 @@
567 ** Send an HTTP redirect back to the designated Index Page.
568 */
569 void fossil_redirect_home(void){
570 cgi_redirectf("%s%s", g.zBaseURL, db_get("index-page", "/index"));
571 }
572
573 /*
574 ** If running as root, chroot to the directory containing the
575 ** repository zRepo and then drop root privileges. Return the
576 ** new repository name.
577 **
578 ** zRepo might be a directory itself. In that case chroot into
579 ** the directory zRepo.
580 **
581 ** Assume the user-id and group-id of the repository, or if zRepo
582 ** is a directory, of that directory.
583 */
584 static char *enter_chroot_jail(char *zRepo){
585 #if !defined(__MINGW32__)
586 if( getuid()==0 ){
587 int i;
588 struct stat sStat;
589 Blob dir;
590 char *zDir;
591
592 file_canonical_name(zRepo, &dir);
593 zDir = blob_str(&dir);
594 if( file_isdir(zDir)==1 ){
595 chdir(zDir);
596 chroot(zDir);
597 zRepo = "/";
598 }else{
599 for(i=strlen(zDir)-1; i>0 && zDir[i]!='/'; i--){}
600 if( zDir[i]!='/' ) fossil_panic("bad repository name: %s", zRepo);
601 zDir[i] = 0;
602 chdir(zDir);
603 chroot(zDir);
604 zDir[i] = '/';
605 zRepo = &zDir[i];
606 }
607 if( stat(zRepo, &sStat)!=0 ){
608 fossil_fatal("cannot stat() repository: %s", zRepo);
609 }
610 setgid(sStat.st_gid);
611 setuid(sStat.st_uid);
612 }
613 #endif
614 return zRepo;
615 }
616
617 /*
618 ** Preconditions:
619 **
620 ** * Environment variables are set up according to the CGI standard.
@@ -580,11 +624,11 @@
624 ** and the actual repository is taken from the first element of PATH_INFO.
625 **
626 ** Process the webpage specified by the PATH_INFO or REQUEST_URI
627 ** environment variable.
628 */
629 static void process_one_web_page(const char *zNotFound){
630 const char *zPathInfo;
631 char *zPath = NULL;
632 int idx;
633 int i;
634
@@ -608,13 +652,17 @@
652 for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){
653 if( !isalnum(zRepo[j]) && zRepo[j]!='-' ) zRepo[j] = '_';
654 }
655
656 if( file_size(zRepo)<1024 ){
657 if( zNotFound ){
658 cgi_redirect(zNotFound);
659 }else{
660 @ <h1>Not Found</h1>
661 cgi_set_status(404, "not found");
662 cgi_reply();
663 }
664 return;
665 }
666 zNewScript = mprintf("%s%.*s", zOldScript, i, zPathInfo);
667 cgi_replace_parameter("PATH_INFO", &zPathInfo[i+1]);
668 zPathInfo += i;
@@ -703,10 +751,11 @@
751 ** the repository, fossil will generate a webpage on stdout based on
752 ** the values of standard CGI environment variables.
753 */
754 void cmd_cgi(void){
755 const char *zFile;
756 const char *zNotFound = 0;
757 Blob config, line, key, value;
758 if( g.argc==3 && strcmp(g.argv[1],"cgi")==0 ){
759 zFile = g.argv[2];
760 }else{
761 zFile = g.argv[1];
@@ -740,19 +789,30 @@
789 continue;
790 }
791 if( blob_eq(&key, "repository:") && blob_token(&line, &value) ){
792 db_open_repository(blob_str(&value));
793 blob_reset(&value);
794 continue;
795 }
796 if( blob_eq(&key, "directory:") && blob_token(&line, &value) ){
797 db_close();
798 g.zRepositoryName = mprintf("%s", blob_str(&value));
799 blob_reset(&value);
800 continue;
801 }
802 if( blob_eq(&key, "notfound:") && blob_token(&line, &value) ){
803 zNotFound = mprintf("%s", blob_str(&value));
804 blob_reset(&value);
805 continue;
806 }
807 }
808 blob_reset(&config);
809 if( g.db==0 && g.zRepositoryName==0 ){
810 cgi_panic("Unable to find or open the project repository");
811 }
812 cgi_init();
813 process_one_web_page(zNotFound);
814 }
815
816 /*
817 ** If g.argv[2] exists then it is either the name of a repository
818 ** that will be used by a server, or else it is a directory that
@@ -789,45 +849,30 @@
849 **
850 ** The argv==6 form is used by the win32 server only.
851 **
852 ** COMMAND: http
853 **
854 ** Usage: %fossil http REPOSITORY [--notfound URL]
855 **
856 ** Handle a single HTTP request appearing on stdin. The resulting webpage
857 ** is delivered on stdout. This method is used to launch an HTTP request
858 ** handler from inetd, for example. The argument is the name of the
859 ** repository.
860 **
861 ** If REPOSITORY is a directory that contains one or more respositories
862 ** with names of the form "*.fossil" then the first element of the URL
863 ** pathname selects among the various repositories. If the pathname does
864 ** not select a valid repository and the --notfound option is available,
865 ** then the server redirects (HTTP code 302) to the URL of --notfound.
866 */
867 void cmd_http(void){
868 const char *zIpAddr;
869 const char *zNotFound;
870 zNotFound = find_option("notfound", 0, 1);
871 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
872 cgi_panic("no repository specified");
873 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
874 g.cgiPanic = 1;
875 g.fullHttpReply = 1;
876 if( g.argc==6 ){
877 g.httpIn = fopen(g.argv[3], "rb");
878 g.httpOut = fopen(g.argv[4], "wb");
@@ -836,12 +881,13 @@
881 g.httpIn = stdin;
882 g.httpOut = stdout;
883 zIpAddr = 0;
884 }
885 find_server_repository(0);
886 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
887 cgi_handle_http_request(zIpAddr);
888 process_one_web_page(zNotFound);
889 }
890
891 /*
892 ** COMMAND: test-http
893 ** Works like the http command but gives setup permission to all users.
@@ -896,15 +942,16 @@
942 ** that contains one or more respositories with names ending in ".fossil".
943 ** In that case, the first element of the URL is used to select among the
944 ** various repositories.
945 */
946 void cmd_webserver(void){
947 int iPort, mxPort; /* Range of TCP ports allowed */
948 const char *zPort; /* Value of the --port option */
949 char *zBrowser; /* Name of web browser program */
950 char *zBrowserCmd = 0; /* Command to launch the web browser */
951 int isUiCmd; /* True if command is "ui", not "server' */
952 const char *zNotFound; /* The --notfound option or NULL */
953
954 #ifdef __MINGW32__
955 const char *zStopperFile; /* Name of file used to terminate server */
956 zStopperFile = find_option("stopper", 0, 1);
957 #endif
@@ -912,10 +959,11 @@
959 g.thTrace = find_option("th-trace", 0, 0)!=0;
960 if( g.thTrace ){
961 blob_zero(&g.thLog);
962 }
963 zPort = find_option("port", "P", 1);
964 zNotFound = find_option("notfound", 0, 1);
965 if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
966 isUiCmd = g.argv[1][0]=='u';
967 find_server_repository(isUiCmd);
968 if( zPort ){
969 iPort = mxPort = atoi(zPort);
@@ -953,17 +1001,18 @@
1001 if( g.fHttpTrace || g.fSqlTrace ){
1002 fprintf(stderr, "====== SERVER pid %d =======\n", getpid());
1003 }
1004 g.cgiPanic = 1;
1005 find_server_repository(isUiCmd);
1006 g.zRepositoryName = enter_chroot_jail(g.zRepositoryName);
1007 cgi_handle_http_request(0);
1008 process_one_web_page(zNotFound);
1009 #else
1010 /* Win32 implementation */
1011 if( isUiCmd ){
1012 zBrowser = db_get("web-browser", "start");
1013 zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
1014 }
1015 db_close();
1016 win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound);
1017 #endif
1018 }
1019
+12 -3
--- src/winhttp.c
+++ src/winhttp.c
@@ -36,10 +36,11 @@
3636
typedef struct HttpRequest HttpRequest;
3737
struct HttpRequest {
3838
int id; /* ID counter */
3939
SOCKET s; /* Socket on which to receive data */
4040
SOCKADDR_IN addr; /* Address from which data is coming */
41
+ const char *zNotFound; /* --notfound option, or an empty string */
4142
};
4243
4344
/*
4445
** Prefix for a temporary file.
4546
*/
@@ -109,13 +110,13 @@
109110
}
110111
wanted -= got;
111112
}
112113
fclose(out);
113114
out = 0;
114
- sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s",
115
+ sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s%s",
115116
g.argv[0], g.zRepositoryName, zRequestFName, zReplyFName,
116
- inet_ntoa(p->addr.sin_addr)
117
+ inet_ntoa(p->addr.sin_addr), p->zNotFound
117118
);
118119
portable_system(zCmd);
119120
in = fopen(zReplyFName, "rb");
120121
if( in ){
121122
while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -137,19 +138,26 @@
137138
** that socket.
138139
*/
139140
void win32_http_server(
140141
int mnPort, int mxPort, /* Range of allowed TCP port numbers */
141142
char *zBrowser, /* Command to launch browser. (Or NULL) */
142
- char *zStopper /* Stop server when this file is exists (Or NULL) */
143
+ char *zStopper, /* Stop server when this file is exists (Or NULL) */
144
+ char *zNotFound /* The --notfound option, or NULL */
143145
){
144146
WSADATA wd;
145147
SOCKET s = INVALID_SOCKET;
146148
SOCKADDR_IN addr;
147149
int idCnt = 0;
148150
int iPort = mnPort;
151
+ char *zNotFoundOption;
149152
150153
if( zStopper ) unlink(zStopper);
154
+ if( zNotFound ){
155
+ zNotFoundOption = mprintf(" --notfound %s", zNotFound);
156
+ }else{
157
+ zNotFoundOption = "";
158
+ }
151159
if( WSAStartup(MAKEWORD(1,1), &wd) ){
152160
fossil_fatal("unable to initialize winsock");
153161
}
154162
while( iPort<=mxPort ){
155163
s = socket(AF_INET, SOCK_STREAM, 0);
@@ -206,12 +214,13 @@
206214
fossil_fatal("out of memory");
207215
}
208216
p->id = ++idCnt;
209217
p->s = client;
210218
p->addr = client_addr;
219
+ p->zNotFound = zNotFoundOption;
211220
_beginthread(win32_process_one_http_request, 0, (void*)p);
212221
}
213222
closesocket(s);
214223
WSACleanup();
215224
}
216225
217226
#endif /* __MINGW32__ -- This code is for win32 only */
218227
--- src/winhttp.c
+++ src/winhttp.c
@@ -36,10 +36,11 @@
36 typedef struct HttpRequest HttpRequest;
37 struct HttpRequest {
38 int id; /* ID counter */
39 SOCKET s; /* Socket on which to receive data */
40 SOCKADDR_IN addr; /* Address from which data is coming */
 
41 };
42
43 /*
44 ** Prefix for a temporary file.
45 */
@@ -109,13 +110,13 @@
109 }
110 wanted -= got;
111 }
112 fclose(out);
113 out = 0;
114 sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s",
115 g.argv[0], g.zRepositoryName, zRequestFName, zReplyFName,
116 inet_ntoa(p->addr.sin_addr)
117 );
118 portable_system(zCmd);
119 in = fopen(zReplyFName, "rb");
120 if( in ){
121 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -137,19 +138,26 @@
137 ** that socket.
138 */
139 void win32_http_server(
140 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
141 char *zBrowser, /* Command to launch browser. (Or NULL) */
142 char *zStopper /* Stop server when this file is exists (Or NULL) */
 
143 ){
144 WSADATA wd;
145 SOCKET s = INVALID_SOCKET;
146 SOCKADDR_IN addr;
147 int idCnt = 0;
148 int iPort = mnPort;
 
149
150 if( zStopper ) unlink(zStopper);
 
 
 
 
 
151 if( WSAStartup(MAKEWORD(1,1), &wd) ){
152 fossil_fatal("unable to initialize winsock");
153 }
154 while( iPort<=mxPort ){
155 s = socket(AF_INET, SOCK_STREAM, 0);
@@ -206,12 +214,13 @@
206 fossil_fatal("out of memory");
207 }
208 p->id = ++idCnt;
209 p->s = client;
210 p->addr = client_addr;
 
211 _beginthread(win32_process_one_http_request, 0, (void*)p);
212 }
213 closesocket(s);
214 WSACleanup();
215 }
216
217 #endif /* __MINGW32__ -- This code is for win32 only */
218
--- src/winhttp.c
+++ src/winhttp.c
@@ -36,10 +36,11 @@
36 typedef struct HttpRequest HttpRequest;
37 struct HttpRequest {
38 int id; /* ID counter */
39 SOCKET s; /* Socket on which to receive data */
40 SOCKADDR_IN addr; /* Address from which data is coming */
41 const char *zNotFound; /* --notfound option, or an empty string */
42 };
43
44 /*
45 ** Prefix for a temporary file.
46 */
@@ -109,13 +110,13 @@
110 }
111 wanted -= got;
112 }
113 fclose(out);
114 out = 0;
115 sprintf(zCmd, "\"%s\" http \"%s\" %s %s %s%s",
116 g.argv[0], g.zRepositoryName, zRequestFName, zReplyFName,
117 inet_ntoa(p->addr.sin_addr), p->zNotFound
118 );
119 portable_system(zCmd);
120 in = fopen(zReplyFName, "rb");
121 if( in ){
122 while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){
@@ -137,19 +138,26 @@
138 ** that socket.
139 */
140 void win32_http_server(
141 int mnPort, int mxPort, /* Range of allowed TCP port numbers */
142 char *zBrowser, /* Command to launch browser. (Or NULL) */
143 char *zStopper, /* Stop server when this file is exists (Or NULL) */
144 char *zNotFound /* The --notfound option, or NULL */
145 ){
146 WSADATA wd;
147 SOCKET s = INVALID_SOCKET;
148 SOCKADDR_IN addr;
149 int idCnt = 0;
150 int iPort = mnPort;
151 char *zNotFoundOption;
152
153 if( zStopper ) unlink(zStopper);
154 if( zNotFound ){
155 zNotFoundOption = mprintf(" --notfound %s", zNotFound);
156 }else{
157 zNotFoundOption = "";
158 }
159 if( WSAStartup(MAKEWORD(1,1), &wd) ){
160 fossil_fatal("unable to initialize winsock");
161 }
162 while( iPort<=mxPort ){
163 s = socket(AF_INET, SOCK_STREAM, 0);
@@ -206,12 +214,13 @@
214 fossil_fatal("out of memory");
215 }
216 p->id = ++idCnt;
217 p->s = client;
218 p->addr = client_addr;
219 p->zNotFound = zNotFoundOption;
220 _beginthread(win32_process_one_http_request, 0, (void*)p);
221 }
222 closesocket(s);
223 WSACleanup();
224 }
225
226 #endif /* __MINGW32__ -- This code is for win32 only */
227
+1 -1
--- www/index.wiki
+++ www/index.wiki
@@ -56,11 +56,11 @@
5656
3. <b>Autosync</b> -
5757
Fossil supports [./concepts.wiki#workflow | "autosync" mode]
5858
which helps to keep projects moving
5959
forward by reducing the amount of needless
6060
[./branching.wiki | forking and merging] often
61
- associated distributed projects.
61
+ associated with distributed projects.
6262
6363
4. <b>Self-Contained</b> -
6464
Fossil is a single stand-alone executable that contains everything
6565
needed to do configuration management.
6666
Installation is trivial: simply download a
6767
--- www/index.wiki
+++ www/index.wiki
@@ -56,11 +56,11 @@
56 3. <b>Autosync</b> -
57 Fossil supports [./concepts.wiki#workflow | "autosync" mode]
58 which helps to keep projects moving
59 forward by reducing the amount of needless
60 [./branching.wiki | forking and merging] often
61 associated distributed projects.
62
63 4. <b>Self-Contained</b> -
64 Fossil is a single stand-alone executable that contains everything
65 needed to do configuration management.
66 Installation is trivial: simply download a
67
--- www/index.wiki
+++ www/index.wiki
@@ -56,11 +56,11 @@
56 3. <b>Autosync</b> -
57 Fossil supports [./concepts.wiki#workflow | "autosync" mode]
58 which helps to keep projects moving
59 forward by reducing the amount of needless
60 [./branching.wiki | forking and merging] often
61 associated with distributed projects.
62
63 4. <b>Self-Contained</b> -
64 Fossil is a single stand-alone executable that contains everything
65 needed to do configuration management.
66 Installation is trivial: simply download a
67

Keyboard Shortcuts

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