Fossil SCM

Merge the experimental ssh:// changes into the trunk.

drh 2010-08-26 13:18 trunk merge
Commit 0a51263a23b658ab98a7ddb064e81422b7ab02bc
-172
--- src/cgi.c
+++ src/cgi.c
@@ -851,145 +851,10 @@
851851
cgi_printf("%s = %s <br />\n",
852852
htmlize(aParamQP[i].zName, -1), htmlize(aParamQP[i].zValue, -1));
853853
}
854854
}
855855
856
-/*
857
-** Write HTML text for an option menu to standard output. zParam
858
-** is the query parameter that the option menu sets. zDflt is the
859
-** initial value of the option menu. Addition arguments are name/value
860
-** pairs that define values on the menu. The list is terminated with
861
-** a single NULL argument.
862
-*/
863
-void cgi_optionmenu(int in, const char *zP, const char *zD, ...){
864
- va_list ap;
865
- char *zName, *zVal;
866
- int dfltSeen = 0;
867
- cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
868
- va_start(ap, zD);
869
- while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
870
- if( strcmp(zVal,zD)==0 ){ dfltSeen = 1; break; }
871
- }
872
- va_end(ap);
873
- if( !dfltSeen ){
874
- if( zD[0] ){
875
- cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
876
- in+2, "", zD, zD);
877
- }else{
878
- cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n", in+2, "");
879
- }
880
- }
881
- va_start(ap, zD);
882
- while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
883
- if( zName[0] ){
884
- cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
885
- in+2, "",
886
- zVal,
887
- strcmp(zVal, zD) ? "" : " selected",
888
- zName
889
- );
890
- }else{
891
- cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
892
- in+2, "",
893
- strcmp(zVal, zD) ? "" : " selected"
894
- );
895
- }
896
- }
897
- va_end(ap);
898
- cgi_printf("%*s</select>\n", in, "");
899
-}
900
-
901
-/*
902
-** This routine works a lot like cgi_optionmenu() except that the list of
903
-** values is contained in an array. Also, the values are just values, not
904
-** name/value pairs as in cgi_optionmenu.
905
-*/
906
-void cgi_v_optionmenu(
907
- int in, /* Indent by this amount */
908
- const char *zP, /* The query parameter name */
909
- const char *zD, /* Default value */
910
- const char **az /* NULL-terminated list of allowed values */
911
-){
912
- const char *zVal;
913
- int i;
914
- cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
915
- for(i=0; az[i]; i++){
916
- if( strcmp(az[i],zD)==0 ) break;
917
- }
918
- if( az[i]==0 ){
919
- if( zD[0]==0 ){
920
- cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
921
- in+2, "");
922
- }else{
923
- cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
924
- in+2, "", zD, zD);
925
- }
926
- }
927
- while( (zVal = *(az++))!=0 ){
928
- if( zVal[0] ){
929
- cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
930
- in+2, "",
931
- zVal,
932
- strcmp(zVal, zD) ? "" : " selected",
933
- zVal
934
- );
935
- }else{
936
- cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
937
- in+2, "",
938
- strcmp(zVal, zD) ? "" : " selected"
939
- );
940
- }
941
- }
942
- cgi_printf("%*s</select>\n", in, "");
943
-}
944
-
945
-/*
946
-** This routine works a lot like cgi_v_optionmenu() except that the list
947
-** is a list of pairs. The first element of each pair is the value used
948
-** internally and the second element is the value displayed to the user.
949
-*/
950
-void cgi_v_optionmenu2(
951
- int in, /* Indent by this amount */
952
- const char *zP, /* The query parameter name */
953
- const char *zD, /* Default value */
954
- const char **az /* NULL-terminated list of allowed values */
955
-){
956
- const char *zVal;
957
- int i;
958
- cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
959
- for(i=0; az[i]; i+=2){
960
- if( strcmp(az[i],zD)==0 ) break;
961
- }
962
- if( az[i]==0 ){
963
- if( zD[0]==0 ){
964
- cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
965
- in+2, "");
966
- }else{
967
- cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
968
- in+2, "", zD, zD);
969
- }
970
- }
971
- while( (zVal = *(az++))!=0 ){
972
- const char *zName = *(az++);
973
- if( zName[0] ){
974
- cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
975
- in+2, "",
976
- zVal,
977
- strcmp(zVal, zD) ? "" : " selected",
978
- zName
979
- );
980
- }else{
981
- cgi_printf("%*s<option value=\"%h\"%s>&nbsp;</option>\n",
982
- in+2, "",
983
- zVal,
984
- strcmp(zVal, zD) ? "" : " selected"
985
- );
986
- }
987
- }
988
- cgi_printf("%*s</select>\n", in, "");
989
-}
990
-
991856
/*
992857
** This routine works like "printf" except that it has the
993858
** extra formatting capabilities such as %h and %t.
994859
*/
995860
void cgi_printf(const char *zFormat, ...){
@@ -1014,22 +879,10 @@
1014879
static void malformed_request(void){
1015880
cgi_set_status(501, "Not Implemented");
1016881
cgi_printf(
1017882
"<html><body>Unrecognized HTTP Request</body></html>\n"
1018883
);
1019
- cgi_reply();
1020
- fossil_exit(0);
1021
-}
1022
-
1023
-/*
1024
-** Send a reply indicating that the HTTP request is forbidden
1025
-*/
1026
-static void forbidden_request(void){
1027
- cgi_set_status(403, "Forbidden");
1028
- cgi_printf(
1029
- "<html><body>Access Denied</body></html>\n"
1030
- );
1031884
cgi_reply();
1032885
fossil_exit(0);
1033886
}
1034887
1035888
/*
@@ -1085,11 +938,10 @@
1085938
void cgi_handle_http_request(const char *zIpAddr){
1086939
char *z, *zToken;
1087940
int i;
1088941
struct sockaddr_in remoteName;
1089942
size_t size = sizeof(struct sockaddr_in);
1090
- int accessTokenSeen = 0;
1091943
char zLine[2000]; /* A single line of input. */
1092944
1093945
g.fullHttpReply = 1;
1094946
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1095947
malformed_request();
@@ -1149,16 +1001,10 @@
11491001
cgi_setenv("HTTP_HOST", zVal);
11501002
}else if( strcmp(zFieldName,"if-none-match:")==0 ){
11511003
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
11521004
}else if( strcmp(zFieldName,"if-modified-since:")==0 ){
11531005
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
1154
- }else if( strcmp(zFieldName,"x-fossil-access-token:")==0 ){
1155
- if( g.zAccessToken ){
1156
- if( strcmp(zVal,g.zAccessToken)==0 ){
1157
- accessTokenSeen = 1;
1158
- }
1159
- }
11601006
}
11611007
#if 0
11621008
else if( strcmp(zFieldName,"referer:")==0 ){
11631009
cgi_setenv("HTTP_REFERER", zVal);
11641010
}else if( strcmp(zFieldName,"user-agent:")==0 ){
@@ -1165,23 +1011,18 @@
11651011
cgi_setenv("HTTP_USER_AGENT", zVal);
11661012
}
11671013
#endif
11681014
}
11691015
1170
- if( g.zAccessToken && !accessTokenSeen ){
1171
- forbidden_request();
1172
- }
1173
-
11741016
cgi_init();
11751017
}
11761018
11771019
#if INTERFACE
11781020
/*
11791021
** Bitmap values for the flags parameter to cgi_http_server().
11801022
*/
11811023
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1182
-#define HTTP_SERVER_STDIN 0x0002 /* Monitor stdin for "quit" */
11831024
11841025
#endif /* INTERFACE */
11851026
11861027
/*
11871028
** Maximum number of child processes that we can have running
@@ -1265,24 +1106,11 @@
12651106
}
12661107
delay.tv_sec = 60;
12671108
delay.tv_usec = 0;
12681109
FD_ZERO(&readfds);
12691110
FD_SET( listener, &readfds);
1270
- if( flags & HTTP_SERVER_STDIN ){
1271
- FD_SET( 0, &readfds);
1272
- }
12731111
select( listener+1, &readfds, 0, 0, &delay);
1274
- if( FD_ISSET(0, &readfds) ){
1275
- int i;
1276
- char zIn[200];
1277
- assert( flags & HTTP_SERVER_STDIN );
1278
- zIn[0] = 0;
1279
- fgets(zIn, sizeof(zIn), stdin);
1280
- for(i=0; zIn[i] && zIn[i]!='\n'; i++){}
1281
- zIn[i] = 0;
1282
- if( strcmp(zIn, "quit")==0 || feof(stdin) ) fossil_exit(0);
1283
- }
12841112
if( FD_ISSET(listener, &readfds) ){
12851113
lenaddr = sizeof(inaddr);
12861114
connection = accept(listener, (struct sockaddr*)&inaddr,
12871115
(socklen_t*) &lenaddr);
12881116
if( connection>=0 ){
12891117
--- src/cgi.c
+++ src/cgi.c
@@ -851,145 +851,10 @@
851 cgi_printf("%s = %s <br />\n",
852 htmlize(aParamQP[i].zName, -1), htmlize(aParamQP[i].zValue, -1));
853 }
854 }
855
856 /*
857 ** Write HTML text for an option menu to standard output. zParam
858 ** is the query parameter that the option menu sets. zDflt is the
859 ** initial value of the option menu. Addition arguments are name/value
860 ** pairs that define values on the menu. The list is terminated with
861 ** a single NULL argument.
862 */
863 void cgi_optionmenu(int in, const char *zP, const char *zD, ...){
864 va_list ap;
865 char *zName, *zVal;
866 int dfltSeen = 0;
867 cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
868 va_start(ap, zD);
869 while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
870 if( strcmp(zVal,zD)==0 ){ dfltSeen = 1; break; }
871 }
872 va_end(ap);
873 if( !dfltSeen ){
874 if( zD[0] ){
875 cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
876 in+2, "", zD, zD);
877 }else{
878 cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n", in+2, "");
879 }
880 }
881 va_start(ap, zD);
882 while( (zName = va_arg(ap, char*))!=0 && (zVal = va_arg(ap, char*))!=0 ){
883 if( zName[0] ){
884 cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
885 in+2, "",
886 zVal,
887 strcmp(zVal, zD) ? "" : " selected",
888 zName
889 );
890 }else{
891 cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
892 in+2, "",
893 strcmp(zVal, zD) ? "" : " selected"
894 );
895 }
896 }
897 va_end(ap);
898 cgi_printf("%*s</select>\n", in, "");
899 }
900
901 /*
902 ** This routine works a lot like cgi_optionmenu() except that the list of
903 ** values is contained in an array. Also, the values are just values, not
904 ** name/value pairs as in cgi_optionmenu.
905 */
906 void cgi_v_optionmenu(
907 int in, /* Indent by this amount */
908 const char *zP, /* The query parameter name */
909 const char *zD, /* Default value */
910 const char **az /* NULL-terminated list of allowed values */
911 ){
912 const char *zVal;
913 int i;
914 cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
915 for(i=0; az[i]; i++){
916 if( strcmp(az[i],zD)==0 ) break;
917 }
918 if( az[i]==0 ){
919 if( zD[0]==0 ){
920 cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
921 in+2, "");
922 }else{
923 cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
924 in+2, "", zD, zD);
925 }
926 }
927 while( (zVal = *(az++))!=0 ){
928 if( zVal[0] ){
929 cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
930 in+2, "",
931 zVal,
932 strcmp(zVal, zD) ? "" : " selected",
933 zVal
934 );
935 }else{
936 cgi_printf("%*s<option value=\"\"%s>&nbsp;</option>\n",
937 in+2, "",
938 strcmp(zVal, zD) ? "" : " selected"
939 );
940 }
941 }
942 cgi_printf("%*s</select>\n", in, "");
943 }
944
945 /*
946 ** This routine works a lot like cgi_v_optionmenu() except that the list
947 ** is a list of pairs. The first element of each pair is the value used
948 ** internally and the second element is the value displayed to the user.
949 */
950 void cgi_v_optionmenu2(
951 int in, /* Indent by this amount */
952 const char *zP, /* The query parameter name */
953 const char *zD, /* Default value */
954 const char **az /* NULL-terminated list of allowed values */
955 ){
956 const char *zVal;
957 int i;
958 cgi_printf("%*s<select size=1 name=\"%s\">\n", in, "", zP);
959 for(i=0; az[i]; i+=2){
960 if( strcmp(az[i],zD)==0 ) break;
961 }
962 if( az[i]==0 ){
963 if( zD[0]==0 ){
964 cgi_printf("%*s<option value=\"\" selected>&nbsp;</option>\n",
965 in+2, "");
966 }else{
967 cgi_printf("%*s<option value=\"%h\" selected>%h</option>\n",
968 in+2, "", zD, zD);
969 }
970 }
971 while( (zVal = *(az++))!=0 ){
972 const char *zName = *(az++);
973 if( zName[0] ){
974 cgi_printf("%*s<option value=\"%h\"%s>%h</option>\n",
975 in+2, "",
976 zVal,
977 strcmp(zVal, zD) ? "" : " selected",
978 zName
979 );
980 }else{
981 cgi_printf("%*s<option value=\"%h\"%s>&nbsp;</option>\n",
982 in+2, "",
983 zVal,
984 strcmp(zVal, zD) ? "" : " selected"
985 );
986 }
987 }
988 cgi_printf("%*s</select>\n", in, "");
989 }
990
991 /*
992 ** This routine works like "printf" except that it has the
993 ** extra formatting capabilities such as %h and %t.
994 */
995 void cgi_printf(const char *zFormat, ...){
@@ -1014,22 +879,10 @@
1014 static void malformed_request(void){
1015 cgi_set_status(501, "Not Implemented");
1016 cgi_printf(
1017 "<html><body>Unrecognized HTTP Request</body></html>\n"
1018 );
1019 cgi_reply();
1020 fossil_exit(0);
1021 }
1022
1023 /*
1024 ** Send a reply indicating that the HTTP request is forbidden
1025 */
1026 static void forbidden_request(void){
1027 cgi_set_status(403, "Forbidden");
1028 cgi_printf(
1029 "<html><body>Access Denied</body></html>\n"
1030 );
1031 cgi_reply();
1032 fossil_exit(0);
1033 }
1034
1035 /*
@@ -1085,11 +938,10 @@
1085 void cgi_handle_http_request(const char *zIpAddr){
1086 char *z, *zToken;
1087 int i;
1088 struct sockaddr_in remoteName;
1089 size_t size = sizeof(struct sockaddr_in);
1090 int accessTokenSeen = 0;
1091 char zLine[2000]; /* A single line of input. */
1092
1093 g.fullHttpReply = 1;
1094 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
1095 malformed_request();
@@ -1149,16 +1001,10 @@
1149 cgi_setenv("HTTP_HOST", zVal);
1150 }else if( strcmp(zFieldName,"if-none-match:")==0 ){
1151 cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
1152 }else if( strcmp(zFieldName,"if-modified-since:")==0 ){
1153 cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
1154 }else if( strcmp(zFieldName,"x-fossil-access-token:")==0 ){
1155 if( g.zAccessToken ){
1156 if( strcmp(zVal,g.zAccessToken)==0 ){
1157 accessTokenSeen = 1;
1158 }
1159 }
1160 }
1161 #if 0
1162 else if( strcmp(zFieldName,"referer:")==0 ){
1163 cgi_setenv("HTTP_REFERER", zVal);
1164 }else if( strcmp(zFieldName,"user-agent:")==0 ){
@@ -1165,23 +1011,18 @@
1165 cgi_setenv("HTTP_USER_AGENT", zVal);
1166 }
1167 #endif
1168 }
1169
1170 if( g.zAccessToken && !accessTokenSeen ){
1171 forbidden_request();
1172 }
1173
1174 cgi_init();
1175 }
1176
1177 #if INTERFACE
1178 /*
1179 ** Bitmap values for the flags parameter to cgi_http_server().
1180 */
1181 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
1182 #define HTTP_SERVER_STDIN 0x0002 /* Monitor stdin for "quit" */
1183
1184 #endif /* INTERFACE */
1185
1186 /*
1187 ** Maximum number of child processes that we can have running
@@ -1265,24 +1106,11 @@
1265 }
1266 delay.tv_sec = 60;
1267 delay.tv_usec = 0;
1268 FD_ZERO(&readfds);
1269 FD_SET( listener, &readfds);
1270 if( flags & HTTP_SERVER_STDIN ){
1271 FD_SET( 0, &readfds);
1272 }
1273 select( listener+1, &readfds, 0, 0, &delay);
1274 if( FD_ISSET(0, &readfds) ){
1275 int i;
1276 char zIn[200];
1277 assert( flags & HTTP_SERVER_STDIN );
1278 zIn[0] = 0;
1279 fgets(zIn, sizeof(zIn), stdin);
1280 for(i=0; zIn[i] && zIn[i]!='\n'; i++){}
1281 zIn[i] = 0;
1282 if( strcmp(zIn, "quit")==0 || feof(stdin) ) fossil_exit(0);
1283 }
1284 if( FD_ISSET(listener, &readfds) ){
1285 lenaddr = sizeof(inaddr);
1286 connection = accept(listener, (struct sockaddr*)&inaddr,
1287 (socklen_t*) &lenaddr);
1288 if( connection>=0 ){
1289
--- src/cgi.c
+++ src/cgi.c
@@ -851,145 +851,10 @@
851 cgi_printf("%s = %s <br />\n",
852 htmlize(aParamQP[i].zName, -1), htmlize(aParamQP[i].zValue, -1));
853 }
854 }
855
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
856 /*
857 ** This routine works like "printf" except that it has the
858 ** extra formatting capabilities such as %h and %t.
859 */
860 void cgi_printf(const char *zFormat, ...){
@@ -1014,22 +879,10 @@
879 static void malformed_request(void){
880 cgi_set_status(501, "Not Implemented");
881 cgi_printf(
882 "<html><body>Unrecognized HTTP Request</body></html>\n"
883 );
 
 
 
 
 
 
 
 
 
 
 
 
884 cgi_reply();
885 fossil_exit(0);
886 }
887
888 /*
@@ -1085,11 +938,10 @@
938 void cgi_handle_http_request(const char *zIpAddr){
939 char *z, *zToken;
940 int i;
941 struct sockaddr_in remoteName;
942 size_t size = sizeof(struct sockaddr_in);
 
943 char zLine[2000]; /* A single line of input. */
944
945 g.fullHttpReply = 1;
946 if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
947 malformed_request();
@@ -1149,16 +1001,10 @@
1001 cgi_setenv("HTTP_HOST", zVal);
1002 }else if( strcmp(zFieldName,"if-none-match:")==0 ){
1003 cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
1004 }else if( strcmp(zFieldName,"if-modified-since:")==0 ){
1005 cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
 
 
 
 
 
 
1006 }
1007 #if 0
1008 else if( strcmp(zFieldName,"referer:")==0 ){
1009 cgi_setenv("HTTP_REFERER", zVal);
1010 }else if( strcmp(zFieldName,"user-agent:")==0 ){
@@ -1165,23 +1011,18 @@
1011 cgi_setenv("HTTP_USER_AGENT", zVal);
1012 }
1013 #endif
1014 }
1015
 
 
 
 
1016 cgi_init();
1017 }
1018
1019 #if INTERFACE
1020 /*
1021 ** Bitmap values for the flags parameter to cgi_http_server().
1022 */
1023 #define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
 
1024
1025 #endif /* INTERFACE */
1026
1027 /*
1028 ** Maximum number of child processes that we can have running
@@ -1265,24 +1106,11 @@
1106 }
1107 delay.tv_sec = 60;
1108 delay.tv_usec = 0;
1109 FD_ZERO(&readfds);
1110 FD_SET( listener, &readfds);
 
 
 
1111 select( listener+1, &readfds, 0, 0, &delay);
 
 
 
 
 
 
 
 
 
 
1112 if( FD_ISSET(listener, &readfds) ){
1113 lenaddr = sizeof(inaddr);
1114 connection = accept(listener, (struct sockaddr*)&inaddr,
1115 (socklen_t*) &lenaddr);
1116 if( connection>=0 ){
1117
+1 -1
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -22,11 +22,11 @@
2222
#include <assert.h>
2323
2424
/*
2525
** Shell-escape the given string. Append the result to a blob.
2626
*/
27
-static void shell_escape(Blob *pBlob, const char *zIn){
27
+void shell_escape(Blob *pBlob, const char *zIn){
2828
int n = blob_size(pBlob);
2929
int k = strlen(zIn);
3030
int i, c;
3131
char *z;
3232
for(i=0; (c = zIn[i])!=0; i++){
3333
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -22,11 +22,11 @@
22 #include <assert.h>
23
24 /*
25 ** Shell-escape the given string. Append the result to a blob.
26 */
27 static void shell_escape(Blob *pBlob, const char *zIn){
28 int n = blob_size(pBlob);
29 int k = strlen(zIn);
30 int i, c;
31 char *z;
32 for(i=0; (c = zIn[i])!=0; i++){
33
--- src/diffcmd.c
+++ src/diffcmd.c
@@ -22,11 +22,11 @@
22 #include <assert.h>
23
24 /*
25 ** Shell-escape the given string. Append the result to a blob.
26 */
27 void shell_escape(Blob *pBlob, const char *zIn){
28 int n = blob_size(pBlob);
29 int k = strlen(zIn);
30 int i, c;
31 char *z;
32 for(i=0; (c = zIn[i])!=0; i++){
33
+22 -5
--- src/http.c
+++ src/http.c
@@ -42,10 +42,13 @@
4242
4343
blob_zero(pLogin);
4444
if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){
4545
return; /* If no login card for users "nobody" and "anonymous" */
4646
}
47
+ if( g.urlIsSsh ){
48
+ return; /* If no login card for SSH: */
49
+ }
4750
blob_zero(&nonce);
4851
blob_zero(&pw);
4952
sha1sum_blob(pPayload, &nonce);
5053
blob_copy(&pw, &nonce);
5154
zLogin = g.urlUser;
@@ -111,15 +114,11 @@
111114
if( g.fHttpTrace ){
112115
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
113116
}else{
114117
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
115118
}
116
- blob_appendf(pHdr, "Content-Length: %d\r\n", blob_size(pPayload));
117
- if( g.zAccessToken ){
118
- blob_appendf(pHdr, "X-Fossil-Access-Token: %s\r\n", g.zAccessToken);
119
- }
120
- blob_appendf(pHdr, "\r\n");
119
+ blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
121120
}
122121
123122
/*
124123
** Sign the content in pSend, compress it, and send it to the server
125124
** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
@@ -138,10 +137,11 @@
138137
int iLength; /* Length of the reply payload */
139138
int rc; /* Result code */
140139
int iHttpVersion; /* Which version of HTTP protocol server uses */
141140
char *zLine; /* A single line of the reply header */
142141
int i; /* Loop counter */
142
+ int isError = 0; /* True if the reply is an error message */
143143
144144
if( transport_open() ){
145145
fossil_fatal(transport_errmsg());
146146
}
147147
@@ -194,10 +194,11 @@
194194
** Read and interpret the server reply
195195
*/
196196
closeConnection = 1;
197197
iLength = -1;
198198
while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
199
+ /* printf("[%s]\n", zLine); fflush(stdout); */
199200
if( strncasecmp(zLine, "http/1.", 7)==0 ){
200201
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
201202
if( rc!=200 && rc!=302 ){
202203
int ii;
203204
for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -231,10 +232,12 @@
231232
fossil_print("redirect to %s\n", &zLine[i]);
232233
url_parse(&zLine[i]);
233234
transport_close();
234235
http_exchange(pSend, pReply, useLogin);
235236
return;
237
+ }else if( strncasecmp(zLine, "content-type: text/html", 23)==0 ){
238
+ isError = 1;
236239
}
237240
}
238241
if( rc!=200 ){
239242
fossil_fatal("\"location:\" missing from 302 redirect reply");
240243
goto write_err;
@@ -249,10 +252,24 @@
249252
}
250253
blob_zero(pReply);
251254
blob_resize(pReply, iLength);
252255
iLength = transport_receive(blob_buffer(pReply), iLength);
253256
blob_resize(pReply, iLength);
257
+ if( isError ){
258
+ char *z;
259
+ int i, j;
260
+ z = blob_str(pReply);
261
+ for(i=j=0; z[i]; i++, j++){
262
+ if( z[i]=='<' ){
263
+ while( z[i] && z[i]!='>' ) i++;
264
+ if( z[i]==0 ) break;
265
+ }
266
+ z[j] = z[i];
267
+ }
268
+ z[j] = 0;
269
+ fossil_fatal("server sends error: %s", z);
270
+ }
254271
if( g.fHttpTrace ){
255272
printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pReply));
256273
}else{
257274
blob_uncompress(pReply, pReply);
258275
}
259276
--- src/http.c
+++ src/http.c
@@ -42,10 +42,13 @@
42
43 blob_zero(pLogin);
44 if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){
45 return; /* If no login card for users "nobody" and "anonymous" */
46 }
 
 
 
47 blob_zero(&nonce);
48 blob_zero(&pw);
49 sha1sum_blob(pPayload, &nonce);
50 blob_copy(&pw, &nonce);
51 zLogin = g.urlUser;
@@ -111,15 +114,11 @@
111 if( g.fHttpTrace ){
112 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
113 }else{
114 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
115 }
116 blob_appendf(pHdr, "Content-Length: %d\r\n", blob_size(pPayload));
117 if( g.zAccessToken ){
118 blob_appendf(pHdr, "X-Fossil-Access-Token: %s\r\n", g.zAccessToken);
119 }
120 blob_appendf(pHdr, "\r\n");
121 }
122
123 /*
124 ** Sign the content in pSend, compress it, and send it to the server
125 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
@@ -138,10 +137,11 @@
138 int iLength; /* Length of the reply payload */
139 int rc; /* Result code */
140 int iHttpVersion; /* Which version of HTTP protocol server uses */
141 char *zLine; /* A single line of the reply header */
142 int i; /* Loop counter */
 
143
144 if( transport_open() ){
145 fossil_fatal(transport_errmsg());
146 }
147
@@ -194,10 +194,11 @@
194 ** Read and interpret the server reply
195 */
196 closeConnection = 1;
197 iLength = -1;
198 while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
 
199 if( strncasecmp(zLine, "http/1.", 7)==0 ){
200 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
201 if( rc!=200 && rc!=302 ){
202 int ii;
203 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -231,10 +232,12 @@
231 fossil_print("redirect to %s\n", &zLine[i]);
232 url_parse(&zLine[i]);
233 transport_close();
234 http_exchange(pSend, pReply, useLogin);
235 return;
 
 
236 }
237 }
238 if( rc!=200 ){
239 fossil_fatal("\"location:\" missing from 302 redirect reply");
240 goto write_err;
@@ -249,10 +252,24 @@
249 }
250 blob_zero(pReply);
251 blob_resize(pReply, iLength);
252 iLength = transport_receive(blob_buffer(pReply), iLength);
253 blob_resize(pReply, iLength);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254 if( g.fHttpTrace ){
255 printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pReply));
256 }else{
257 blob_uncompress(pReply, pReply);
258 }
259
--- src/http.c
+++ src/http.c
@@ -42,10 +42,13 @@
42
43 blob_zero(pLogin);
44 if( g.urlUser==0 || strcmp(g.urlUser, "anonymous")==0 ){
45 return; /* If no login card for users "nobody" and "anonymous" */
46 }
47 if( g.urlIsSsh ){
48 return; /* If no login card for SSH: */
49 }
50 blob_zero(&nonce);
51 blob_zero(&pw);
52 sha1sum_blob(pPayload, &nonce);
53 blob_copy(&pw, &nonce);
54 zLogin = g.urlUser;
@@ -111,15 +114,11 @@
114 if( g.fHttpTrace ){
115 blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
116 }else{
117 blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
118 }
119 blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
 
 
 
 
120 }
121
122 /*
123 ** Sign the content in pSend, compress it, and send it to the server
124 ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
@@ -138,10 +137,11 @@
137 int iLength; /* Length of the reply payload */
138 int rc; /* Result code */
139 int iHttpVersion; /* Which version of HTTP protocol server uses */
140 char *zLine; /* A single line of the reply header */
141 int i; /* Loop counter */
142 int isError = 0; /* True if the reply is an error message */
143
144 if( transport_open() ){
145 fossil_fatal(transport_errmsg());
146 }
147
@@ -194,10 +194,11 @@
194 ** Read and interpret the server reply
195 */
196 closeConnection = 1;
197 iLength = -1;
198 while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
199 /* printf("[%s]\n", zLine); fflush(stdout); */
200 if( strncasecmp(zLine, "http/1.", 7)==0 ){
201 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
202 if( rc!=200 && rc!=302 ){
203 int ii;
204 for(ii=7; zLine[ii] && zLine[ii]!=' '; ii++){}
@@ -231,10 +232,12 @@
232 fossil_print("redirect to %s\n", &zLine[i]);
233 url_parse(&zLine[i]);
234 transport_close();
235 http_exchange(pSend, pReply, useLogin);
236 return;
237 }else if( strncasecmp(zLine, "content-type: text/html", 23)==0 ){
238 isError = 1;
239 }
240 }
241 if( rc!=200 ){
242 fossil_fatal("\"location:\" missing from 302 redirect reply");
243 goto write_err;
@@ -249,10 +252,24 @@
252 }
253 blob_zero(pReply);
254 blob_resize(pReply, iLength);
255 iLength = transport_receive(blob_buffer(pReply), iLength);
256 blob_resize(pReply, iLength);
257 if( isError ){
258 char *z;
259 int i, j;
260 z = blob_str(pReply);
261 for(i=j=0; z[i]; i++, j++){
262 if( z[i]=='<' ){
263 while( z[i] && z[i]!='>' ) i++;
264 if( z[i]==0 ) break;
265 }
266 z[j] = z[i];
267 }
268 z[j] = 0;
269 fossil_fatal("server sends error: %s", z);
270 }
271 if( g.fHttpTrace ){
272 printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pReply));
273 }else{
274 blob_uncompress(pReply, pReply);
275 }
276
--- src/http_transport.c
+++ src/http_transport.c
@@ -38,10 +38,19 @@
3838
char *zOutFile; /* Name of outbound file for FILE: */
3939
char *zInFile; /* Name of inbound file for FILE: */
4040
} transport = {
4141
0, 0, 0, 0, 0, 0, 0
4242
};
43
+
44
+/*
45
+** Information about the connection to the SSH subprocess when
46
+** using the ssh:// sync method.
47
+*/
48
+static int sshPid; /* Process id of ssh subprocess */
49
+static int sshIn; /* From ssh subprocess to this process */
50
+static FILE *sshOut; /* From this to ssh subprocess */
51
+
4352
4453
/*
4554
** Return the current transport error message.
4655
*/
4756
const char *transport_errmsg(void){
@@ -63,49 +72,53 @@
6372
if( resetFlag ){
6473
transport.nSent = 0;
6574
transport.nRcvd = 0;
6675
}
6776
}
77
+
78
+/*
79
+** Read text from sshIn. Zero-terminate and remove trailing
80
+** whitespace.
81
+*/
82
+static void sshin_read(char *zBuf, int szBuf){
83
+ int got;
84
+ zBuf[0] = 0;
85
+ got = read(sshIn, zBuf, szBuf-1);
86
+ while( got>=0 ){
87
+ zBuf[got] = 0;
88
+ if( got==0 || !isspace(zBuf[got-1]) ) break;
89
+ got--;
90
+ }
91
+}
6892
6993
/*
7094
** Global initialization of the transport layer
7195
*/
7296
void transport_global_startup(void){
7397
if( g.urlIsSsh ){
7498
char *zCmd;
75
- int i;
76
- char zIn[200];
99
+ char zIn[20];
77100
#ifdef __MINGW32__
78101
fossil_fatal("the ssh:// sync method is currently only supported on unix");
79102
#endif
80103
if( g.urlUser && g.urlUser[0] ){
81
- zCmd = mprintf(
82
- "ssh -L127.0.0.1:%d:127.0.0.1:%d %s@%s "
83
- "\"fossil server -P %d '%s'\"",
84
- g.urlPort, g.urlPort, g.urlUser, g.urlSshHost, g.urlPort, g.urlPath
85
- );
104
+ zCmd = mprintf("ssh -e none %s@%s", g.urlUser, g.urlName);
86105
}else{
87
- zCmd = mprintf(
88
- "ssh -L127.0.0.1:%d:127.0.0.1:%d %s \"fossil sshd -P %d '%s'\"",
89
- g.urlPort, g.urlPort, g.urlSshHost, g.urlPort, g.urlPath
90
- );
91
- }
92
- printf("%s\n", zCmd);
93
- popen2(zCmd, &g.sshIn, &g.sshOut, &g.sshPid);
94
- if( g.sshPid==0 ){
106
+ zCmd = mprintf("ssh -e none %s", g.urlName);
107
+ }
108
+ /* printf("%s\n", zCmd); */
109
+ popen2(zCmd, &sshIn, &sshOut, &sshPid);
110
+ if( sshPid==0 ){
95111
fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
96112
}
97113
free(zCmd);
98
- zIn[0] = 0;
99
- fgets(zIn, sizeof(zIn), g.sshIn);
100
- for(i=0; zIn[i] && zIn[i]!='\n'; i++){}
101
- zIn[i] = 0;
102
- if( memcmp(zIn, "Access-Token: ", 14)!=0 ){
103
- pclose2(g.sshIn, g.sshOut, g.sshPid);
104
- fossil_fatal("failed to start ssh tunnel");
105
- }
106
- g.zAccessToken = mprintf("%s", &zIn[14]);
114
+ fprintf(sshOut, "echo test\n");
115
+ fflush(sshOut);
116
+ sshin_read(zIn, sizeof(zIn));
117
+ if( memcmp(zIn, "test", 4)!=0 ){
118
+ fossil_fatal("ssh connection failed");
119
+ }
107120
}
108121
}
109122
110123
/*
111124
** Open a connection to the server. The server is defined by the following
@@ -118,11 +131,21 @@
118131
** Return the number of errors.
119132
*/
120133
int transport_open(void){
121134
int rc = 0;
122135
if( transport.isOpen==0 ){
123
- if( g.urlIsHttps ){
136
+ if( g.urlIsSsh ){
137
+ Blob cmd;
138
+ blob_zero(&cmd);
139
+ shell_escape(&cmd, g.urlFossil);
140
+ blob_append(&cmd, " test-http ", -1);
141
+ shell_escape(&cmd, g.urlPath);
142
+ /* fprintf(stdout, "%s\n", blob_str(&cmd)); */
143
+ fprintf(sshOut, "%s\n", blob_str(&cmd));
144
+ fflush(sshOut);
145
+ blob_reset(&cmd);
146
+ }else if( g.urlIsHttps ){
124147
#ifdef FOSSIL_ENABLE_SSL
125148
rc = ssl_open();
126149
if( rc==0 ) transport.isOpen = 1;
127150
#else
128151
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
@@ -156,11 +179,13 @@
156179
free(transport.pBuf);
157180
transport.pBuf = 0;
158181
transport.nAlloc = 0;
159182
transport.nUsed = 0;
160183
transport.iCursor = 0;
161
- if( g.urlIsHttps ){
184
+ if( g.urlIsSsh ){
185
+ /* No-op */
186
+ }else if( g.urlIsHttps ){
162187
#ifdef FOSSIL_ENABLE_SSL
163188
ssl_close();
164189
#endif
165190
}else if( g.urlIsFile ){
166191
if( transport.pFile ){
@@ -183,11 +208,16 @@
183208
*/
184209
void transport_send(Blob *toSend){
185210
char *z = blob_buffer(toSend);
186211
int n = blob_size(toSend);
187212
transport.nSent += n;
188
- if( g.urlIsHttps ){
213
+ if( g.urlIsSsh ){
214
+ int sent;
215
+ sent = fwrite(z, 1, n, sshOut);
216
+ fflush(sshOut);
217
+ /* printf("sent %d of %d bytes\n", sent, n); fflush(stdout); */
218
+ }else if( g.urlIsHttps ){
189219
#ifdef FOSSIL_ENABLE_SSL
190220
int sent;
191221
while( n>0 ){
192222
sent = ssl_send(0, z, n);
193223
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
@@ -211,11 +241,13 @@
211241
/*
212242
** This routine is called when the outbound message is complete and
213243
** it is time to being recieving a reply.
214244
*/
215245
void transport_flip(void){
216
- if( g.urlIsFile ){
246
+ if( g.urlIsSsh ){
247
+ fprintf(sshOut, "\n\n");
248
+ }else if( g.urlIsFile ){
217249
char *zCmd;
218250
fclose(transport.pFile);
219251
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1",
220252
g.argv[0], g.urlName, transport.zOutFile, transport.zInFile
221253
);
@@ -232,10 +264,41 @@
232264
void transport_rewind(void){
233265
if( g.urlIsFile ){
234266
transport_close();
235267
}
236268
}
269
+
270
+/*
271
+** Read N bytes of content directly from the wire and write into
272
+** the buffer.
273
+*/
274
+static int transport_fetch(char *zBuf, int N){
275
+ int got;
276
+ if( sshIn ){
277
+ int x;
278
+ int wanted = N;
279
+ got = 0;
280
+ while( wanted>0 ){
281
+ x = read(sshIn, &zBuf[got], wanted);
282
+ if( x<=0 ) break;
283
+ got += x;
284
+ wanted -= x;
285
+ }
286
+ }else if( g.urlIsHttps ){
287
+ #ifdef FOSSIL_ENABLE_SSL
288
+ got = ssl_receive(0, zBuf, N);
289
+ #else
290
+ got = 0;
291
+ #endif
292
+ }else if( g.urlIsFile ){
293
+ got = fread(zBuf, 1, N, transport.pFile);
294
+ }else{
295
+ got = socket_receive(0, zBuf, N);
296
+ }
297
+ /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
298
+ return got;
299
+}
237300
238301
/*
239302
** Read N bytes of content from the wire and store in the supplied buffer.
240303
** Return the number of bytes actually received.
241304
*/
@@ -242,10 +305,11 @@
242305
int transport_receive(char *zBuf, int N){
243306
int onHand; /* Bytes current held in the transport buffer */
244307
int nByte = 0; /* Bytes of content received */
245308
246309
onHand = transport.nUsed - transport.iCursor;
310
+ /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
247311
if( onHand>0 ){
248312
int toMove = onHand;
249313
if( toMove>N ) toMove = N;
250314
/* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
251315
memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -257,24 +321,11 @@
257321
N -= toMove;
258322
zBuf += toMove;
259323
nByte += toMove;
260324
}
261325
if( N>0 ){
262
- int got;
263
- if( g.urlIsHttps ){
264
- #ifdef FOSSIL_ENABLE_SSL
265
- got = ssl_receive(0, zBuf, N);
266
- /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
267
- #else
268
- got = 0;
269
- #endif
270
- }else if( g.urlIsFile ){
271
- got = fread(zBuf, 1, N, transport.pFile);
272
- }else{
273
- got = socket_receive(0, zBuf, N);
274
- /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
275
- }
326
+ int got = transport_fetch(zBuf, N);
276327
if( got>0 ){
277328
nByte += got;
278329
transport.nRcvd += got;
279330
}
280331
}
@@ -308,11 +359,11 @@
308359
pNew = realloc(transport.pBuf, transport.nAlloc);
309360
if( pNew==0 ) fossil_panic("out of memory");
310361
transport.pBuf = pNew;
311362
}
312363
if( N>0 ){
313
- i = transport_receive(&transport.pBuf[transport.nUsed], N);
364
+ i = transport_fetch(&transport.pBuf[transport.nUsed], N);
314365
if( i>0 ){
315366
transport.nUsed += i;
316367
}
317368
}
318369
}
@@ -354,19 +405,19 @@
354405
/* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
355406
return &transport.pBuf[iStart];
356407
}
357408
358409
void transport_global_shutdown(void){
359
- if( g.urlIsSsh && g.sshPid ){
410
+ if( g.urlIsSsh && sshPid ){
360411
printf("Closing SSH tunnel: ");
361412
fflush(stdout);
362
- pclose2(g.sshIn, g.sshOut, g.sshPid);
363
- g.sshPid = 0;
413
+ pclose2(sshIn, sshOut, sshPid);
414
+ sshPid = 0;
364415
}
365416
if( g.urlIsHttps ){
366417
#ifdef FOSSIL_ENABLE_SSL
367418
ssl_global_shutdown();
368419
#endif
369420
}else{
370421
socket_global_shutdown();
371422
}
372423
}
373424
--- src/http_transport.c
+++ src/http_transport.c
@@ -38,10 +38,19 @@
38 char *zOutFile; /* Name of outbound file for FILE: */
39 char *zInFile; /* Name of inbound file for FILE: */
40 } transport = {
41 0, 0, 0, 0, 0, 0, 0
42 };
 
 
 
 
 
 
 
 
 
43
44 /*
45 ** Return the current transport error message.
46 */
47 const char *transport_errmsg(void){
@@ -63,49 +72,53 @@
63 if( resetFlag ){
64 transport.nSent = 0;
65 transport.nRcvd = 0;
66 }
67 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
69 /*
70 ** Global initialization of the transport layer
71 */
72 void transport_global_startup(void){
73 if( g.urlIsSsh ){
74 char *zCmd;
75 int i;
76 char zIn[200];
77 #ifdef __MINGW32__
78 fossil_fatal("the ssh:// sync method is currently only supported on unix");
79 #endif
80 if( g.urlUser && g.urlUser[0] ){
81 zCmd = mprintf(
82 "ssh -L127.0.0.1:%d:127.0.0.1:%d %s@%s "
83 "\"fossil server -P %d '%s'\"",
84 g.urlPort, g.urlPort, g.urlUser, g.urlSshHost, g.urlPort, g.urlPath
85 );
86 }else{
87 zCmd = mprintf(
88 "ssh -L127.0.0.1:%d:127.0.0.1:%d %s \"fossil sshd -P %d '%s'\"",
89 g.urlPort, g.urlPort, g.urlSshHost, g.urlPort, g.urlPath
90 );
91 }
92 printf("%s\n", zCmd);
93 popen2(zCmd, &g.sshIn, &g.sshOut, &g.sshPid);
94 if( g.sshPid==0 ){
95 fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
96 }
97 free(zCmd);
98 zIn[0] = 0;
99 fgets(zIn, sizeof(zIn), g.sshIn);
100 for(i=0; zIn[i] && zIn[i]!='\n'; i++){}
101 zIn[i] = 0;
102 if( memcmp(zIn, "Access-Token: ", 14)!=0 ){
103 pclose2(g.sshIn, g.sshOut, g.sshPid);
104 fossil_fatal("failed to start ssh tunnel");
105 }
106 g.zAccessToken = mprintf("%s", &zIn[14]);
107 }
108 }
109
110 /*
111 ** Open a connection to the server. The server is defined by the following
@@ -118,11 +131,21 @@
118 ** Return the number of errors.
119 */
120 int transport_open(void){
121 int rc = 0;
122 if( transport.isOpen==0 ){
123 if( g.urlIsHttps ){
 
 
 
 
 
 
 
 
 
 
124 #ifdef FOSSIL_ENABLE_SSL
125 rc = ssl_open();
126 if( rc==0 ) transport.isOpen = 1;
127 #else
128 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
@@ -156,11 +179,13 @@
156 free(transport.pBuf);
157 transport.pBuf = 0;
158 transport.nAlloc = 0;
159 transport.nUsed = 0;
160 transport.iCursor = 0;
161 if( g.urlIsHttps ){
 
 
162 #ifdef FOSSIL_ENABLE_SSL
163 ssl_close();
164 #endif
165 }else if( g.urlIsFile ){
166 if( transport.pFile ){
@@ -183,11 +208,16 @@
183 */
184 void transport_send(Blob *toSend){
185 char *z = blob_buffer(toSend);
186 int n = blob_size(toSend);
187 transport.nSent += n;
188 if( g.urlIsHttps ){
 
 
 
 
 
189 #ifdef FOSSIL_ENABLE_SSL
190 int sent;
191 while( n>0 ){
192 sent = ssl_send(0, z, n);
193 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
@@ -211,11 +241,13 @@
211 /*
212 ** This routine is called when the outbound message is complete and
213 ** it is time to being recieving a reply.
214 */
215 void transport_flip(void){
216 if( g.urlIsFile ){
 
 
217 char *zCmd;
218 fclose(transport.pFile);
219 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1",
220 g.argv[0], g.urlName, transport.zOutFile, transport.zInFile
221 );
@@ -232,10 +264,41 @@
232 void transport_rewind(void){
233 if( g.urlIsFile ){
234 transport_close();
235 }
236 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
237
238 /*
239 ** Read N bytes of content from the wire and store in the supplied buffer.
240 ** Return the number of bytes actually received.
241 */
@@ -242,10 +305,11 @@
242 int transport_receive(char *zBuf, int N){
243 int onHand; /* Bytes current held in the transport buffer */
244 int nByte = 0; /* Bytes of content received */
245
246 onHand = transport.nUsed - transport.iCursor;
 
247 if( onHand>0 ){
248 int toMove = onHand;
249 if( toMove>N ) toMove = N;
250 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
251 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -257,24 +321,11 @@
257 N -= toMove;
258 zBuf += toMove;
259 nByte += toMove;
260 }
261 if( N>0 ){
262 int got;
263 if( g.urlIsHttps ){
264 #ifdef FOSSIL_ENABLE_SSL
265 got = ssl_receive(0, zBuf, N);
266 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
267 #else
268 got = 0;
269 #endif
270 }else if( g.urlIsFile ){
271 got = fread(zBuf, 1, N, transport.pFile);
272 }else{
273 got = socket_receive(0, zBuf, N);
274 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
275 }
276 if( got>0 ){
277 nByte += got;
278 transport.nRcvd += got;
279 }
280 }
@@ -308,11 +359,11 @@
308 pNew = realloc(transport.pBuf, transport.nAlloc);
309 if( pNew==0 ) fossil_panic("out of memory");
310 transport.pBuf = pNew;
311 }
312 if( N>0 ){
313 i = transport_receive(&transport.pBuf[transport.nUsed], N);
314 if( i>0 ){
315 transport.nUsed += i;
316 }
317 }
318 }
@@ -354,19 +405,19 @@
354 /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
355 return &transport.pBuf[iStart];
356 }
357
358 void transport_global_shutdown(void){
359 if( g.urlIsSsh && g.sshPid ){
360 printf("Closing SSH tunnel: ");
361 fflush(stdout);
362 pclose2(g.sshIn, g.sshOut, g.sshPid);
363 g.sshPid = 0;
364 }
365 if( g.urlIsHttps ){
366 #ifdef FOSSIL_ENABLE_SSL
367 ssl_global_shutdown();
368 #endif
369 }else{
370 socket_global_shutdown();
371 }
372 }
373
--- src/http_transport.c
+++ src/http_transport.c
@@ -38,10 +38,19 @@
38 char *zOutFile; /* Name of outbound file for FILE: */
39 char *zInFile; /* Name of inbound file for FILE: */
40 } transport = {
41 0, 0, 0, 0, 0, 0, 0
42 };
43
44 /*
45 ** Information about the connection to the SSH subprocess when
46 ** using the ssh:// sync method.
47 */
48 static int sshPid; /* Process id of ssh subprocess */
49 static int sshIn; /* From ssh subprocess to this process */
50 static FILE *sshOut; /* From this to ssh subprocess */
51
52
53 /*
54 ** Return the current transport error message.
55 */
56 const char *transport_errmsg(void){
@@ -63,49 +72,53 @@
72 if( resetFlag ){
73 transport.nSent = 0;
74 transport.nRcvd = 0;
75 }
76 }
77
78 /*
79 ** Read text from sshIn. Zero-terminate and remove trailing
80 ** whitespace.
81 */
82 static void sshin_read(char *zBuf, int szBuf){
83 int got;
84 zBuf[0] = 0;
85 got = read(sshIn, zBuf, szBuf-1);
86 while( got>=0 ){
87 zBuf[got] = 0;
88 if( got==0 || !isspace(zBuf[got-1]) ) break;
89 got--;
90 }
91 }
92
93 /*
94 ** Global initialization of the transport layer
95 */
96 void transport_global_startup(void){
97 if( g.urlIsSsh ){
98 char *zCmd;
99 char zIn[20];
 
100 #ifdef __MINGW32__
101 fossil_fatal("the ssh:// sync method is currently only supported on unix");
102 #endif
103 if( g.urlUser && g.urlUser[0] ){
104 zCmd = mprintf("ssh -e none %s@%s", g.urlUser, g.urlName);
 
 
 
 
105 }else{
106 zCmd = mprintf("ssh -e none %s", g.urlName);
107 }
108 /* printf("%s\n", zCmd); */
109 popen2(zCmd, &sshIn, &sshOut, &sshPid);
110 if( sshPid==0 ){
 
 
 
111 fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
112 }
113 free(zCmd);
114 fprintf(sshOut, "echo test\n");
115 fflush(sshOut);
116 sshin_read(zIn, sizeof(zIn));
117 if( memcmp(zIn, "test", 4)!=0 ){
118 fossil_fatal("ssh connection failed");
119 }
 
 
 
120 }
121 }
122
123 /*
124 ** Open a connection to the server. The server is defined by the following
@@ -118,11 +131,21 @@
131 ** Return the number of errors.
132 */
133 int transport_open(void){
134 int rc = 0;
135 if( transport.isOpen==0 ){
136 if( g.urlIsSsh ){
137 Blob cmd;
138 blob_zero(&cmd);
139 shell_escape(&cmd, g.urlFossil);
140 blob_append(&cmd, " test-http ", -1);
141 shell_escape(&cmd, g.urlPath);
142 /* fprintf(stdout, "%s\n", blob_str(&cmd)); */
143 fprintf(sshOut, "%s\n", blob_str(&cmd));
144 fflush(sshOut);
145 blob_reset(&cmd);
146 }else if( g.urlIsHttps ){
147 #ifdef FOSSIL_ENABLE_SSL
148 rc = ssl_open();
149 if( rc==0 ) transport.isOpen = 1;
150 #else
151 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
@@ -156,11 +179,13 @@
179 free(transport.pBuf);
180 transport.pBuf = 0;
181 transport.nAlloc = 0;
182 transport.nUsed = 0;
183 transport.iCursor = 0;
184 if( g.urlIsSsh ){
185 /* No-op */
186 }else if( g.urlIsHttps ){
187 #ifdef FOSSIL_ENABLE_SSL
188 ssl_close();
189 #endif
190 }else if( g.urlIsFile ){
191 if( transport.pFile ){
@@ -183,11 +208,16 @@
208 */
209 void transport_send(Blob *toSend){
210 char *z = blob_buffer(toSend);
211 int n = blob_size(toSend);
212 transport.nSent += n;
213 if( g.urlIsSsh ){
214 int sent;
215 sent = fwrite(z, 1, n, sshOut);
216 fflush(sshOut);
217 /* printf("sent %d of %d bytes\n", sent, n); fflush(stdout); */
218 }else if( g.urlIsHttps ){
219 #ifdef FOSSIL_ENABLE_SSL
220 int sent;
221 while( n>0 ){
222 sent = ssl_send(0, z, n);
223 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
@@ -211,11 +241,13 @@
241 /*
242 ** This routine is called when the outbound message is complete and
243 ** it is time to being recieving a reply.
244 */
245 void transport_flip(void){
246 if( g.urlIsSsh ){
247 fprintf(sshOut, "\n\n");
248 }else if( g.urlIsFile ){
249 char *zCmd;
250 fclose(transport.pFile);
251 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1",
252 g.argv[0], g.urlName, transport.zOutFile, transport.zInFile
253 );
@@ -232,10 +264,41 @@
264 void transport_rewind(void){
265 if( g.urlIsFile ){
266 transport_close();
267 }
268 }
269
270 /*
271 ** Read N bytes of content directly from the wire and write into
272 ** the buffer.
273 */
274 static int transport_fetch(char *zBuf, int N){
275 int got;
276 if( sshIn ){
277 int x;
278 int wanted = N;
279 got = 0;
280 while( wanted>0 ){
281 x = read(sshIn, &zBuf[got], wanted);
282 if( x<=0 ) break;
283 got += x;
284 wanted -= x;
285 }
286 }else if( g.urlIsHttps ){
287 #ifdef FOSSIL_ENABLE_SSL
288 got = ssl_receive(0, zBuf, N);
289 #else
290 got = 0;
291 #endif
292 }else if( g.urlIsFile ){
293 got = fread(zBuf, 1, N, transport.pFile);
294 }else{
295 got = socket_receive(0, zBuf, N);
296 }
297 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
298 return got;
299 }
300
301 /*
302 ** Read N bytes of content from the wire and store in the supplied buffer.
303 ** Return the number of bytes actually received.
304 */
@@ -242,10 +305,11 @@
305 int transport_receive(char *zBuf, int N){
306 int onHand; /* Bytes current held in the transport buffer */
307 int nByte = 0; /* Bytes of content received */
308
309 onHand = transport.nUsed - transport.iCursor;
310 /* printf("request %d with %d on hand\n", N, onHand); fflush(stdout); */
311 if( onHand>0 ){
312 int toMove = onHand;
313 if( toMove>N ) toMove = N;
314 /* printf("bytes on hand: %d of %d\n", toMove, N); fflush(stdout); */
315 memcpy(zBuf, &transport.pBuf[transport.iCursor], toMove);
@@ -257,24 +321,11 @@
321 N -= toMove;
322 zBuf += toMove;
323 nByte += toMove;
324 }
325 if( N>0 ){
326 int got = transport_fetch(zBuf, N);
 
 
 
 
 
 
 
 
 
 
 
 
 
327 if( got>0 ){
328 nByte += got;
329 transport.nRcvd += got;
330 }
331 }
@@ -308,11 +359,11 @@
359 pNew = realloc(transport.pBuf, transport.nAlloc);
360 if( pNew==0 ) fossil_panic("out of memory");
361 transport.pBuf = pNew;
362 }
363 if( N>0 ){
364 i = transport_fetch(&transport.pBuf[transport.nUsed], N);
365 if( i>0 ){
366 transport.nUsed += i;
367 }
368 }
369 }
@@ -354,19 +405,19 @@
405 /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
406 return &transport.pBuf[iStart];
407 }
408
409 void transport_global_shutdown(void){
410 if( g.urlIsSsh && sshPid ){
411 printf("Closing SSH tunnel: ");
412 fflush(stdout);
413 pclose2(sshIn, sshOut, sshPid);
414 sshPid = 0;
415 }
416 if( g.urlIsHttps ){
417 #ifdef FOSSIL_ENABLE_SSL
418 ssl_global_shutdown();
419 #endif
420 }else{
421 socket_global_shutdown();
422 }
423 }
424
+12 -25
--- src/main.c
+++ src/main.c
@@ -83,30 +83,25 @@
8383
FILE *httpOut; /* Send HTTP output here */
8484
int xlinkClusterOnly; /* Set when cloning. Only process clusters */
8585
int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
8686
int *aCommitFile; /* Array of files to be committed */
8787
int markPrivate; /* All new artifacts are private if true */
88
- char *zAccessToken; /* X-Fossil-Access-Token HTTP header field */
89
- int sshPid; /* Process id of ssh subprocess */
90
- FILE *sshIn; /* From ssh subprocess to this */
91
- FILE *sshOut; /* From this to ssh subprocess */
9288
9389
int urlIsFile; /* True if a "file:" url */
9490
int urlIsHttps; /* True if a "https:" url */
9591
int urlIsSsh; /* True if an "ssh:" url */
9692
char *urlName; /* Hostname for http: or filename for file: */
97
- char *urlSshHost; /* Hostname for ssh: tunnels */
9893
char *urlHostname; /* The HOST: parameter on http headers */
9994
char *urlProtocol; /* "http" or "https" */
10095
int urlPort; /* TCP port number for http: or https: */
10196
int urlDfltPort; /* The default port for the given protocol */
102
- int urlSshPort; /* TCP port for SSH */
10397
char *urlPath; /* Pathname for http: */
10498
char *urlUser; /* User id for http: */
10599
char *urlPasswd; /* Password for http: */
106100
char *urlCanonical; /* Canonical representation of the URL */
107101
char *urlProxyAuth; /* Proxy-Authorizer: string */
102
+ char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
108103
int dontKeepUrl; /* Do not persist the URL */
109104
110105
const char *zLogin; /* Login name. "" if not logged in. */
111106
int noPswd; /* Logged in without password (on 127.0.0.1) */
112107
int userUid; /* Integer user id */
@@ -921,14 +916,14 @@
921916
*/
922917
void cmd_http(void){
923918
const char *zIpAddr;
924919
const char *zNotFound;
925920
zNotFound = find_option("notfound", 0, 1);
921
+ g.cgiOutput = 1;
926922
if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
927
- cgi_panic("no repository specified");
923
+ fossil_fatal("no repository specified");
928924
}
929
- g.cgiOutput = 1;
930925
g.fullHttpReply = 1;
931926
if( g.argc==6 ){
932927
g.httpIn = fopen(g.argv[3], "rb");
933928
g.httpOut = fopen(g.argv[4], "wb");
934929
zIpAddr = g.argv[5];
@@ -942,16 +937,24 @@
942937
cgi_handle_http_request(zIpAddr);
943938
process_one_web_page(zNotFound);
944939
}
945940
946941
/*
942
+** Note that the following command is used by ssh:// processing.
943
+**
947944
** COMMAND: test-http
948945
** Works like the http command but gives setup permission to all users.
949946
*/
950947
void cmd_test_http(void){
951948
login_set_capabilities("s");
952
- cmd_http();
949
+ g.httpIn = stdin;
950
+ g.httpOut = stdout;
951
+ find_server_repository(0);
952
+ g.cgiOutput = 1;
953
+ g.fullHttpReply = 1;
954
+ cgi_handle_http_request(0);
955
+ process_one_web_page(0);
953956
}
954957
955958
#ifndef __MINGW32__
956959
#if !defined(__DARWIN__) && !defined(__APPLE__)
957960
/*
@@ -976,11 +979,10 @@
976979
}
977980
#endif
978981
#endif
979982
980983
/*
981
-** COMMAND: sshd
982984
** COMMAND: server
983985
** COMMAND: ui
984986
**
985987
** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
986988
** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
@@ -997,13 +999,10 @@
997999
**
9981000
** In the "server" command, the REPOSITORY can be a directory (aka folder)
9991001
** that contains one or more respositories with names ending in ".fossil".
10001002
** In that case, the first element of the URL is used to select among the
10011003
** various repositories.
1002
-**
1003
-** The "ui" or "server" verb can also be "sshd". This is used internally
1004
-** by the ssh:// sync method.
10051004
*/
10061005
void cmd_webserver(void){
10071006
int iPort, mxPort; /* Range of TCP ports allowed */
10081007
const char *zPort; /* Value of the --port option */
10091008
char *zBrowser; /* Name of web browser program */
@@ -1031,22 +1030,10 @@
10311030
iPort = mxPort = atoi(zPort);
10321031
}else{
10331032
iPort = db_get_int("http-port", 8080);
10341033
mxPort = iPort+100;
10351034
}
1036
- if( g.argv[1][0]=='s' && g.argv[1][1]=='s' ){
1037
- /* For ssh://, output a random "access token" that must appear in
1038
- ** the header of every HTTP request. HTTP requests without the
1039
- ** correct access token reply with 403 Forbidden. The access token
1040
- ** prevents any clients other than the one client that launched the
1041
- ** remote server via SSH from accessing the remote server.
1042
- */
1043
- g.zAccessToken = db_text(0, "SELECT lower(hex(randomblob(20)))");
1044
- printf("Access-Token: %s\n", g.zAccessToken);
1045
- fflush(stdout);
1046
- flags |= HTTP_SERVER_LOCALHOST | HTTP_SERVER_STDIN;
1047
- }
10481035
#ifndef __MINGW32__
10491036
/* Unix implementation */
10501037
if( isUiCmd ){
10511038
#if !defined(__DARWIN__) && !defined(__APPLE__)
10521039
zBrowser = db_get("web-browser", 0);
10531040
--- src/main.c
+++ src/main.c
@@ -83,30 +83,25 @@
83 FILE *httpOut; /* Send HTTP output here */
84 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
85 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
86 int *aCommitFile; /* Array of files to be committed */
87 int markPrivate; /* All new artifacts are private if true */
88 char *zAccessToken; /* X-Fossil-Access-Token HTTP header field */
89 int sshPid; /* Process id of ssh subprocess */
90 FILE *sshIn; /* From ssh subprocess to this */
91 FILE *sshOut; /* From this to ssh subprocess */
92
93 int urlIsFile; /* True if a "file:" url */
94 int urlIsHttps; /* True if a "https:" url */
95 int urlIsSsh; /* True if an "ssh:" url */
96 char *urlName; /* Hostname for http: or filename for file: */
97 char *urlSshHost; /* Hostname for ssh: tunnels */
98 char *urlHostname; /* The HOST: parameter on http headers */
99 char *urlProtocol; /* "http" or "https" */
100 int urlPort; /* TCP port number for http: or https: */
101 int urlDfltPort; /* The default port for the given protocol */
102 int urlSshPort; /* TCP port for SSH */
103 char *urlPath; /* Pathname for http: */
104 char *urlUser; /* User id for http: */
105 char *urlPasswd; /* Password for http: */
106 char *urlCanonical; /* Canonical representation of the URL */
107 char *urlProxyAuth; /* Proxy-Authorizer: string */
 
108 int dontKeepUrl; /* Do not persist the URL */
109
110 const char *zLogin; /* Login name. "" if not logged in. */
111 int noPswd; /* Logged in without password (on 127.0.0.1) */
112 int userUid; /* Integer user id */
@@ -921,14 +916,14 @@
921 */
922 void cmd_http(void){
923 const char *zIpAddr;
924 const char *zNotFound;
925 zNotFound = find_option("notfound", 0, 1);
 
926 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
927 cgi_panic("no repository specified");
928 }
929 g.cgiOutput = 1;
930 g.fullHttpReply = 1;
931 if( g.argc==6 ){
932 g.httpIn = fopen(g.argv[3], "rb");
933 g.httpOut = fopen(g.argv[4], "wb");
934 zIpAddr = g.argv[5];
@@ -942,16 +937,24 @@
942 cgi_handle_http_request(zIpAddr);
943 process_one_web_page(zNotFound);
944 }
945
946 /*
 
 
947 ** COMMAND: test-http
948 ** Works like the http command but gives setup permission to all users.
949 */
950 void cmd_test_http(void){
951 login_set_capabilities("s");
952 cmd_http();
 
 
 
 
 
 
953 }
954
955 #ifndef __MINGW32__
956 #if !defined(__DARWIN__) && !defined(__APPLE__)
957 /*
@@ -976,11 +979,10 @@
976 }
977 #endif
978 #endif
979
980 /*
981 ** COMMAND: sshd
982 ** COMMAND: server
983 ** COMMAND: ui
984 **
985 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
986 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
@@ -997,13 +999,10 @@
997 **
998 ** In the "server" command, the REPOSITORY can be a directory (aka folder)
999 ** that contains one or more respositories with names ending in ".fossil".
1000 ** In that case, the first element of the URL is used to select among the
1001 ** various repositories.
1002 **
1003 ** The "ui" or "server" verb can also be "sshd". This is used internally
1004 ** by the ssh:// sync method.
1005 */
1006 void cmd_webserver(void){
1007 int iPort, mxPort; /* Range of TCP ports allowed */
1008 const char *zPort; /* Value of the --port option */
1009 char *zBrowser; /* Name of web browser program */
@@ -1031,22 +1030,10 @@
1031 iPort = mxPort = atoi(zPort);
1032 }else{
1033 iPort = db_get_int("http-port", 8080);
1034 mxPort = iPort+100;
1035 }
1036 if( g.argv[1][0]=='s' && g.argv[1][1]=='s' ){
1037 /* For ssh://, output a random "access token" that must appear in
1038 ** the header of every HTTP request. HTTP requests without the
1039 ** correct access token reply with 403 Forbidden. The access token
1040 ** prevents any clients other than the one client that launched the
1041 ** remote server via SSH from accessing the remote server.
1042 */
1043 g.zAccessToken = db_text(0, "SELECT lower(hex(randomblob(20)))");
1044 printf("Access-Token: %s\n", g.zAccessToken);
1045 fflush(stdout);
1046 flags |= HTTP_SERVER_LOCALHOST | HTTP_SERVER_STDIN;
1047 }
1048 #ifndef __MINGW32__
1049 /* Unix implementation */
1050 if( isUiCmd ){
1051 #if !defined(__DARWIN__) && !defined(__APPLE__)
1052 zBrowser = db_get("web-browser", 0);
1053
--- src/main.c
+++ src/main.c
@@ -83,30 +83,25 @@
83 FILE *httpOut; /* Send HTTP output here */
84 int xlinkClusterOnly; /* Set when cloning. Only process clusters */
85 int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */
86 int *aCommitFile; /* Array of files to be committed */
87 int markPrivate; /* All new artifacts are private if true */
 
 
 
 
88
89 int urlIsFile; /* True if a "file:" url */
90 int urlIsHttps; /* True if a "https:" url */
91 int urlIsSsh; /* True if an "ssh:" url */
92 char *urlName; /* Hostname for http: or filename for file: */
 
93 char *urlHostname; /* The HOST: parameter on http headers */
94 char *urlProtocol; /* "http" or "https" */
95 int urlPort; /* TCP port number for http: or https: */
96 int urlDfltPort; /* The default port for the given protocol */
 
97 char *urlPath; /* Pathname for http: */
98 char *urlUser; /* User id for http: */
99 char *urlPasswd; /* Password for http: */
100 char *urlCanonical; /* Canonical representation of the URL */
101 char *urlProxyAuth; /* Proxy-Authorizer: string */
102 char *urlFossil; /* The path of the ?fossil=path suffix on ssh: */
103 int dontKeepUrl; /* Do not persist the URL */
104
105 const char *zLogin; /* Login name. "" if not logged in. */
106 int noPswd; /* Logged in without password (on 127.0.0.1) */
107 int userUid; /* Integer user id */
@@ -921,14 +916,14 @@
916 */
917 void cmd_http(void){
918 const char *zIpAddr;
919 const char *zNotFound;
920 zNotFound = find_option("notfound", 0, 1);
921 g.cgiOutput = 1;
922 if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){
923 fossil_fatal("no repository specified");
924 }
 
925 g.fullHttpReply = 1;
926 if( g.argc==6 ){
927 g.httpIn = fopen(g.argv[3], "rb");
928 g.httpOut = fopen(g.argv[4], "wb");
929 zIpAddr = g.argv[5];
@@ -942,16 +937,24 @@
937 cgi_handle_http_request(zIpAddr);
938 process_one_web_page(zNotFound);
939 }
940
941 /*
942 ** Note that the following command is used by ssh:// processing.
943 **
944 ** COMMAND: test-http
945 ** Works like the http command but gives setup permission to all users.
946 */
947 void cmd_test_http(void){
948 login_set_capabilities("s");
949 g.httpIn = stdin;
950 g.httpOut = stdout;
951 find_server_repository(0);
952 g.cgiOutput = 1;
953 g.fullHttpReply = 1;
954 cgi_handle_http_request(0);
955 process_one_web_page(0);
956 }
957
958 #ifndef __MINGW32__
959 #if !defined(__DARWIN__) && !defined(__APPLE__)
960 /*
@@ -976,11 +979,10 @@
979 }
980 #endif
981 #endif
982
983 /*
 
984 ** COMMAND: server
985 ** COMMAND: ui
986 **
987 ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
988 ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
@@ -997,13 +999,10 @@
999 **
1000 ** In the "server" command, the REPOSITORY can be a directory (aka folder)
1001 ** that contains one or more respositories with names ending in ".fossil".
1002 ** In that case, the first element of the URL is used to select among the
1003 ** various repositories.
 
 
 
1004 */
1005 void cmd_webserver(void){
1006 int iPort, mxPort; /* Range of TCP ports allowed */
1007 const char *zPort; /* Value of the --port option */
1008 char *zBrowser; /* Name of web browser program */
@@ -1031,22 +1030,10 @@
1030 iPort = mxPort = atoi(zPort);
1031 }else{
1032 iPort = db_get_int("http-port", 8080);
1033 mxPort = iPort+100;
1034 }
 
 
 
 
 
 
 
 
 
 
 
 
1035 #ifndef __MINGW32__
1036 /* Unix implementation */
1037 if( isUiCmd ){
1038 #if !defined(__DARWIN__) && !defined(__APPLE__)
1039 zBrowser = db_get("web-browser", 0);
1040
+95 -6
--- src/popen.c
+++ src/popen.c
@@ -18,26 +18,115 @@
1818
** This file contains an implementation of a bi-directional popen().
1919
*/
2020
#include "config.h"
2121
#include "popen.h"
2222
23
+#ifdef __MINGW32__
24
+/*
25
+** Print a fatal error and quit.
26
+*/
27
+static void win32_fatal_error(const char *zMsg){
28
+ fossil_fatal("%s");
29
+}
30
+#endif
31
+
32
+
33
+
34
+#ifdef __MINGW32__
35
+/*
36
+** On windows, create a child process and specify the stdin, stdout,
37
+** and stderr channels for that process to use.
38
+**
39
+** Return the number of errors.
40
+*/
41
+static int win32_create_child_process(
42
+ char *zCmd, /* The command that the child process will run */
43
+ HANDLE hIn, /* Standard input */
44
+ HANDLE hOut, /* Standard output */
45
+ HANDLE hErr, /* Standard error */
46
+ DWORD *pChildPid /* OUT: Child process handle */
47
+){
48
+ STARTUPINFO si;
49
+ PROCESS_INFORMATION pi;
50
+ BOOL rc;
51
+
52
+ memset(&si, 0, sizeof(si));
53
+ si.cb = sizeof(si);
54
+ si.dwFlags = STARTF_USESTDHANDLES;
55
+ SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, TRUE);
56
+ si.hStdInput = hIn;
57
+ SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, TRUE);
58
+ si.hStdOutput = hOut;
59
+ SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, TRUE);
60
+ si.hStdError = hErr;
61
+ rc = CreateProcess(
62
+ NULL, /* Application Name */
63
+ zCmd, /* Command-line */
64
+ NULL, /* Process attributes */
65
+ NULL, /* Thread attributes */
66
+ TRUE, /* Inherit Handles */
67
+ 0, /* Create flags */
68
+ NULL, /* Environment */
69
+ NULL, /* Current directory */
70
+ &si, /* Startup Info */
71
+ &pi /* Process Info */
72
+ );
73
+ if( rc ){
74
+ CloseHandle( pi.hProcess );
75
+ CloseHandle( pi.hThread );
76
+ *pChildPid = pi.dwProcessId;
77
+ }else{
78
+ win32_fatal_error("cannot create child process");
79
+ }
80
+ return rc!=0;
81
+}
82
+#endif
83
+
2384
/*
2485
** Create a child process running shell command "zCmd". *ppOut is
2586
** a FILE that becomes the standard input of the child process.
2687
** (The caller writes to *ppOut in order to send text to the child.)
2788
** *ppIn is stdout from the child process. (The caller
2889
** reads from *ppIn in order to receive input from the child.)
90
+** Note that *ppIn is an unbuffered file descriptor, not a FILE.
2991
** The process ID of the child is written into *pChildPid.
3092
**
3193
** Return the number of errors.
3294
*/
33
-int popen2(const char *zCmd, FILE **ppIn, FILE **ppOut, int *pChildPid){
95
+int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
3496
#ifdef __MINGW32__
35
- return 1; /* Not implemented on windows, yet */
97
+ HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
98
+ SECURITY_ATTRIBUTES saAttr;
99
+ DWORD childPid;
100
+ int fd;
101
+
102
+ saAttr.nLength = sizeof(saAttr);
103
+ saAttr.bInheritHandle = TRUE;
104
+ saAttr.lpSecurityDescriptor = NULL;
105
+ hStderr = GetStdHandle(STD_ERROR_HANDLE);
106
+ if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
107
+ win32_fatal_error("cannot create pipe for stdout");
108
+ }
109
+ SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
110
+
111
+ if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
112
+ win32_fatal_error("cannot create pipe for stdin");
113
+ }
114
+ SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
115
+
116
+ win32_create_child_process((char*)zCmd,
117
+ hStdinRd, hStdoutWr, hStderr,&childPid);
118
+ *pChildPid = childPid;
119
+ *pfdIn = _open_osfhandle(hStdoutRd, 0);
120
+ fd = _open_osfhandle(hStdoutWr, 0);
121
+ *ppOut = _fdopen(fd, "w");
122
+ CloseHandle(hStdinRd);
123
+ CloseHandle(hStdoutWr);
124
+ return 0;
36125
#else
37126
int pin[2], pout[2];
38
- *ppIn = 0;
127
+ *pfdIn = 0;
39128
*ppOut = 0;
40129
*pChildPid = 0;
41130
42131
if( pipe(pin)<0 ){
43132
return 1;
@@ -69,11 +158,11 @@
69158
execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
70159
return 1;
71160
}else{
72161
/* This is the parent process */
73162
close(pin[1]);
74
- *ppIn = fdopen(pin[0], "r");
163
+ *pfdIn = pin[0];
75164
close(pout[0]);
76165
*ppOut = fdopen(pout[1], "w");
77166
return 0;
78167
}
79168
#endif
@@ -81,14 +170,14 @@
81170
82171
/*
83172
** Close the connection to a child process previously created using
84173
** popen2(). Kill off the child process, then close the pipes.
85174
*/
86
-void pclose2(FILE *pIn, FILE *pOut, int childPid){
175
+void pclose2(int fdIn, FILE *pOut, int childPid){
87176
#ifdef __MINGW32__
88177
/* Not implemented, yet */
89178
#else
90179
kill(childPid, SIGINT);
91
- fclose(pIn);
180
+ close(fdIn);
92181
fclose(pOut);
93182
#endif
94183
}
95184
--- src/popen.c
+++ src/popen.c
@@ -18,26 +18,115 @@
18 ** This file contains an implementation of a bi-directional popen().
19 */
20 #include "config.h"
21 #include "popen.h"
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23 /*
24 ** Create a child process running shell command "zCmd". *ppOut is
25 ** a FILE that becomes the standard input of the child process.
26 ** (The caller writes to *ppOut in order to send text to the child.)
27 ** *ppIn is stdout from the child process. (The caller
28 ** reads from *ppIn in order to receive input from the child.)
 
29 ** The process ID of the child is written into *pChildPid.
30 **
31 ** Return the number of errors.
32 */
33 int popen2(const char *zCmd, FILE **ppIn, FILE **ppOut, int *pChildPid){
34 #ifdef __MINGW32__
35 return 1; /* Not implemented on windows, yet */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36 #else
37 int pin[2], pout[2];
38 *ppIn = 0;
39 *ppOut = 0;
40 *pChildPid = 0;
41
42 if( pipe(pin)<0 ){
43 return 1;
@@ -69,11 +158,11 @@
69 execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
70 return 1;
71 }else{
72 /* This is the parent process */
73 close(pin[1]);
74 *ppIn = fdopen(pin[0], "r");
75 close(pout[0]);
76 *ppOut = fdopen(pout[1], "w");
77 return 0;
78 }
79 #endif
@@ -81,14 +170,14 @@
81
82 /*
83 ** Close the connection to a child process previously created using
84 ** popen2(). Kill off the child process, then close the pipes.
85 */
86 void pclose2(FILE *pIn, FILE *pOut, int childPid){
87 #ifdef __MINGW32__
88 /* Not implemented, yet */
89 #else
90 kill(childPid, SIGINT);
91 fclose(pIn);
92 fclose(pOut);
93 #endif
94 }
95
--- src/popen.c
+++ src/popen.c
@@ -18,26 +18,115 @@
18 ** This file contains an implementation of a bi-directional popen().
19 */
20 #include "config.h"
21 #include "popen.h"
22
23 #ifdef __MINGW32__
24 /*
25 ** Print a fatal error and quit.
26 */
27 static void win32_fatal_error(const char *zMsg){
28 fossil_fatal("%s");
29 }
30 #endif
31
32
33
34 #ifdef __MINGW32__
35 /*
36 ** On windows, create a child process and specify the stdin, stdout,
37 ** and stderr channels for that process to use.
38 **
39 ** Return the number of errors.
40 */
41 static int win32_create_child_process(
42 char *zCmd, /* The command that the child process will run */
43 HANDLE hIn, /* Standard input */
44 HANDLE hOut, /* Standard output */
45 HANDLE hErr, /* Standard error */
46 DWORD *pChildPid /* OUT: Child process handle */
47 ){
48 STARTUPINFO si;
49 PROCESS_INFORMATION pi;
50 BOOL rc;
51
52 memset(&si, 0, sizeof(si));
53 si.cb = sizeof(si);
54 si.dwFlags = STARTF_USESTDHANDLES;
55 SetHandleInformation(hIn, HANDLE_FLAG_INHERIT, TRUE);
56 si.hStdInput = hIn;
57 SetHandleInformation(hOut, HANDLE_FLAG_INHERIT, TRUE);
58 si.hStdOutput = hOut;
59 SetHandleInformation(hErr, HANDLE_FLAG_INHERIT, TRUE);
60 si.hStdError = hErr;
61 rc = CreateProcess(
62 NULL, /* Application Name */
63 zCmd, /* Command-line */
64 NULL, /* Process attributes */
65 NULL, /* Thread attributes */
66 TRUE, /* Inherit Handles */
67 0, /* Create flags */
68 NULL, /* Environment */
69 NULL, /* Current directory */
70 &si, /* Startup Info */
71 &pi /* Process Info */
72 );
73 if( rc ){
74 CloseHandle( pi.hProcess );
75 CloseHandle( pi.hThread );
76 *pChildPid = pi.dwProcessId;
77 }else{
78 win32_fatal_error("cannot create child process");
79 }
80 return rc!=0;
81 }
82 #endif
83
84 /*
85 ** Create a child process running shell command "zCmd". *ppOut is
86 ** a FILE that becomes the standard input of the child process.
87 ** (The caller writes to *ppOut in order to send text to the child.)
88 ** *ppIn is stdout from the child process. (The caller
89 ** reads from *ppIn in order to receive input from the child.)
90 ** Note that *ppIn is an unbuffered file descriptor, not a FILE.
91 ** The process ID of the child is written into *pChildPid.
92 **
93 ** Return the number of errors.
94 */
95 int popen2(const char *zCmd, int *pfdIn, FILE **ppOut, int *pChildPid){
96 #ifdef __MINGW32__
97 HANDLE hStdinRd, hStdinWr, hStdoutRd, hStdoutWr, hStderr;
98 SECURITY_ATTRIBUTES saAttr;
99 DWORD childPid;
100 int fd;
101
102 saAttr.nLength = sizeof(saAttr);
103 saAttr.bInheritHandle = TRUE;
104 saAttr.lpSecurityDescriptor = NULL;
105 hStderr = GetStdHandle(STD_ERROR_HANDLE);
106 if( !CreatePipe(&hStdoutRd, &hStdoutWr, &saAttr, 4096) ){
107 win32_fatal_error("cannot create pipe for stdout");
108 }
109 SetHandleInformation( hStdoutRd, HANDLE_FLAG_INHERIT, FALSE);
110
111 if( !CreatePipe(&hStdinRd, &hStdinWr, &saAttr, 4096) ){
112 win32_fatal_error("cannot create pipe for stdin");
113 }
114 SetHandleInformation( hStdinWr, HANDLE_FLAG_INHERIT, FALSE);
115
116 win32_create_child_process((char*)zCmd,
117 hStdinRd, hStdoutWr, hStderr,&childPid);
118 *pChildPid = childPid;
119 *pfdIn = _open_osfhandle(hStdoutRd, 0);
120 fd = _open_osfhandle(hStdoutWr, 0);
121 *ppOut = _fdopen(fd, "w");
122 CloseHandle(hStdinRd);
123 CloseHandle(hStdoutWr);
124 return 0;
125 #else
126 int pin[2], pout[2];
127 *pfdIn = 0;
128 *ppOut = 0;
129 *pChildPid = 0;
130
131 if( pipe(pin)<0 ){
132 return 1;
@@ -69,11 +158,11 @@
158 execl("/bin/sh", "/bin/sh", "-c", zCmd, (char*)0);
159 return 1;
160 }else{
161 /* This is the parent process */
162 close(pin[1]);
163 *pfdIn = pin[0];
164 close(pout[0]);
165 *ppOut = fdopen(pout[1], "w");
166 return 0;
167 }
168 #endif
@@ -81,14 +170,14 @@
170
171 /*
172 ** Close the connection to a child process previously created using
173 ** popen2(). Kill off the child process, then close the pipes.
174 */
175 void pclose2(int fdIn, FILE *pOut, int childPid){
176 #ifdef __MINGW32__
177 /* Not implemented, yet */
178 #else
179 kill(childPid, SIGINT);
180 close(fdIn);
181 fclose(pOut);
182 #endif
183 }
184
+43 -16
--- src/url.c
+++ src/url.c
@@ -35,15 +35,13 @@
3535
**
3636
** g.urlIsFile True if FILE:
3737
** g.urlIsHttps True if HTTPS:
3838
** g.urlIsSsh True if SSH:
3939
** g.urlProtocol "http" or "https" or "file"
40
-** g.urlName Hostname for HTTP: or HTTPS:. Filename for FILE:
41
-** g.urlSshHost Hostname for SSH: tunnel
40
+** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
4241
** g.urlPort TCP port number for HTTP or HTTPS.
4342
** g.urlDfltPort Default TCP port number (80 or 443).
44
-** g.urlSshPort TCP port for SSH: tunnel
4543
** g.urlPath Path name for HTTP or HTTPS.
4644
** g.urlUser Userid.
4745
** g.urlPasswd Password.
4846
** g.urlHostname HOST:PORT or just HOST if port is the default.
4947
** g.urlCanonical The URL in canonical form, omitting the password
@@ -52,11 +50,11 @@
5250
**
5351
** http://userid:password@host:port/path?query#fragment
5452
**
5553
** SSH url format is:
5654
**
57
-** ssh://userid@host:port/fullpath
55
+** ssh://userid@host:port/path?fossil=path/to/fossil.exe
5856
**
5957
*/
6058
void url_parse(const char *zUrl){
6159
int i, j, c;
6260
char *zFile = 0;
@@ -120,19 +118,19 @@
120118
);
121119
}
122120
free(zLogin);
123121
}else if( strncmp(zUrl, "ssh://", 6)==0 ){
124122
char *zLogin;
125
- int r;
123
+ char *zExe;
124
+ int i, j;
126125
g.urlIsFile = 0;
127126
g.urlIsSsh = 1;
128127
g.urlProtocol = "ssh";
129
- sqlite3_randomness(sizeof(r), &r);
130
- g.urlPort = 18800 + (r & 0x7fffff)%2000;
131
- g.urlDfltPort = 80;
132
- g.urlName = "127.0.0.1";
133
- g.urlHostname = g.urlName;
128
+ g.urlPort = 22;
129
+ g.urlDfltPort = 22;
130
+ g.urlPasswd = "(not-used)";
131
+ g.urlFossil = "fossil";
134132
for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
135133
if( c=='@' ){
136134
for(j=6; j<i && zUrl[j]!=':'; j++){}
137135
g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
138136
dehttpize(g.urlUser);
@@ -139,25 +137,54 @@
139137
if( j<i ){
140138
g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
141139
dehttpize(g.urlPasswd);
142140
}
143141
for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
144
- g.urlSshHost = mprintf("%.*s", j-i-1, &zUrl[i+1]);
142
+ g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
145143
i = j;
146144
zLogin = mprintf("%t@", g.urlUser);
147145
}else{
148
- g.urlSshHost = mprintf("%.*s", i-6, &zUrl[6]);
146
+ g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
149147
zLogin = mprintf("");
150148
}
151
- url_tolower(g.urlSshHost);
149
+ url_tolower(g.urlName);
150
+ g.urlHostname = g.urlName;
152151
g.urlPath = mprintf(&zUrl[i+1]);
152
+ for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
153
+ if( g.urlPath[i] ){
154
+ g.urlPath[i] = 0;
155
+ i++;
156
+ }
157
+ zExe = mprintf("");
158
+ while( g.urlPath[i]!=0 ){
159
+ char *zName, *zValue;
160
+ zName = &g.urlPath[i];
161
+ zValue = zName;
162
+ while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
163
+ if( g.urlPath[i]=='=' ){
164
+ g.urlPath[i] = 0;
165
+ i++;
166
+ zValue = &g.urlPath[i];
167
+ while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
168
+ }
169
+ if( g.urlPath[i] ){
170
+ g.urlPath[i] = 0;
171
+ i++;
172
+ }
173
+ if( strcmp(zName,"fossil")==0 ){
174
+ g.urlFossil = zValue;
175
+ dehttpize(g.urlFossil);
176
+ zExe = mprintf("?fossil=%T", g.urlFossil);
177
+ }
178
+ }
153179
dehttpize(g.urlPath);
154180
g.urlCanonical = mprintf(
155
- "ssh://%s%T/%T",
156
- zLogin, g.urlSshHost, g.urlPath
181
+ "ssh://%s%T/%T%s",
182
+ zLogin, g.urlName, g.urlPath, zExe
157183
);
158184
free(zLogin);
185
+ free(zExe);
159186
}else if( strncmp(zUrl, "file:", 5)==0 ){
160187
g.urlIsFile = 1;
161188
if( zUrl[5]=='/' && zUrl[6]=='/' ){
162189
i = 7;
163190
}else{
@@ -205,18 +232,18 @@
205232
printf("g.urlIsFile = %d\n", g.urlIsFile);
206233
printf("g.urlIsHttps = %d\n", g.urlIsHttps);
207234
printf("g.urlIsSsh = %d\n", g.urlIsSsh);
208235
printf("g.urlProtocol = %s\n", g.urlProtocol);
209236
printf("g.urlName = %s\n", g.urlName);
210
- printf("g.urlSshHost = %s\n", g.urlSshHost);
211237
printf("g.urlPort = %d\n", g.urlPort);
212238
printf("g.urlDfltPort = %d\n", g.urlDfltPort);
213239
printf("g.urlHostname = %s\n", g.urlHostname);
214240
printf("g.urlPath = %s\n", g.urlPath);
215241
printf("g.urlUser = %s\n", g.urlUser);
216242
printf("g.urlPasswd = %s\n", g.urlPasswd);
217243
printf("g.urlCanonical = %s\n", g.urlCanonical);
244
+ printf("g.urlFossil = %s\n", g.urlFossil);
218245
if( g.urlIsFile || g.urlIsSsh ) break;
219246
if( i==0 ){
220247
printf("********\n");
221248
url_enable_proxy("Using proxy: ");
222249
}
223250
--- src/url.c
+++ src/url.c
@@ -35,15 +35,13 @@
35 **
36 ** g.urlIsFile True if FILE:
37 ** g.urlIsHttps True if HTTPS:
38 ** g.urlIsSsh True if SSH:
39 ** g.urlProtocol "http" or "https" or "file"
40 ** g.urlName Hostname for HTTP: or HTTPS:. Filename for FILE:
41 ** g.urlSshHost Hostname for SSH: tunnel
42 ** g.urlPort TCP port number for HTTP or HTTPS.
43 ** g.urlDfltPort Default TCP port number (80 or 443).
44 ** g.urlSshPort TCP port for SSH: tunnel
45 ** g.urlPath Path name for HTTP or HTTPS.
46 ** g.urlUser Userid.
47 ** g.urlPasswd Password.
48 ** g.urlHostname HOST:PORT or just HOST if port is the default.
49 ** g.urlCanonical The URL in canonical form, omitting the password
@@ -52,11 +50,11 @@
52 **
53 ** http://userid:password@host:port/path?query#fragment
54 **
55 ** SSH url format is:
56 **
57 ** ssh://userid@host:port/fullpath
58 **
59 */
60 void url_parse(const char *zUrl){
61 int i, j, c;
62 char *zFile = 0;
@@ -120,19 +118,19 @@
120 );
121 }
122 free(zLogin);
123 }else if( strncmp(zUrl, "ssh://", 6)==0 ){
124 char *zLogin;
125 int r;
 
126 g.urlIsFile = 0;
127 g.urlIsSsh = 1;
128 g.urlProtocol = "ssh";
129 sqlite3_randomness(sizeof(r), &r);
130 g.urlPort = 18800 + (r & 0x7fffff)%2000;
131 g.urlDfltPort = 80;
132 g.urlName = "127.0.0.1";
133 g.urlHostname = g.urlName;
134 for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
135 if( c=='@' ){
136 for(j=6; j<i && zUrl[j]!=':'; j++){}
137 g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
138 dehttpize(g.urlUser);
@@ -139,25 +137,54 @@
139 if( j<i ){
140 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
141 dehttpize(g.urlPasswd);
142 }
143 for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
144 g.urlSshHost = mprintf("%.*s", j-i-1, &zUrl[i+1]);
145 i = j;
146 zLogin = mprintf("%t@", g.urlUser);
147 }else{
148 g.urlSshHost = mprintf("%.*s", i-6, &zUrl[6]);
149 zLogin = mprintf("");
150 }
151 url_tolower(g.urlSshHost);
 
152 g.urlPath = mprintf(&zUrl[i+1]);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153 dehttpize(g.urlPath);
154 g.urlCanonical = mprintf(
155 "ssh://%s%T/%T",
156 zLogin, g.urlSshHost, g.urlPath
157 );
158 free(zLogin);
 
159 }else if( strncmp(zUrl, "file:", 5)==0 ){
160 g.urlIsFile = 1;
161 if( zUrl[5]=='/' && zUrl[6]=='/' ){
162 i = 7;
163 }else{
@@ -205,18 +232,18 @@
205 printf("g.urlIsFile = %d\n", g.urlIsFile);
206 printf("g.urlIsHttps = %d\n", g.urlIsHttps);
207 printf("g.urlIsSsh = %d\n", g.urlIsSsh);
208 printf("g.urlProtocol = %s\n", g.urlProtocol);
209 printf("g.urlName = %s\n", g.urlName);
210 printf("g.urlSshHost = %s\n", g.urlSshHost);
211 printf("g.urlPort = %d\n", g.urlPort);
212 printf("g.urlDfltPort = %d\n", g.urlDfltPort);
213 printf("g.urlHostname = %s\n", g.urlHostname);
214 printf("g.urlPath = %s\n", g.urlPath);
215 printf("g.urlUser = %s\n", g.urlUser);
216 printf("g.urlPasswd = %s\n", g.urlPasswd);
217 printf("g.urlCanonical = %s\n", g.urlCanonical);
 
218 if( g.urlIsFile || g.urlIsSsh ) break;
219 if( i==0 ){
220 printf("********\n");
221 url_enable_proxy("Using proxy: ");
222 }
223
--- src/url.c
+++ src/url.c
@@ -35,15 +35,13 @@
35 **
36 ** g.urlIsFile True if FILE:
37 ** g.urlIsHttps True if HTTPS:
38 ** g.urlIsSsh True if SSH:
39 ** g.urlProtocol "http" or "https" or "file"
40 ** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
 
41 ** g.urlPort TCP port number for HTTP or HTTPS.
42 ** g.urlDfltPort Default TCP port number (80 or 443).
 
43 ** g.urlPath Path name for HTTP or HTTPS.
44 ** g.urlUser Userid.
45 ** g.urlPasswd Password.
46 ** g.urlHostname HOST:PORT or just HOST if port is the default.
47 ** g.urlCanonical The URL in canonical form, omitting the password
@@ -52,11 +50,11 @@
50 **
51 ** http://userid:password@host:port/path?query#fragment
52 **
53 ** SSH url format is:
54 **
55 ** ssh://userid@host:port/path?fossil=path/to/fossil.exe
56 **
57 */
58 void url_parse(const char *zUrl){
59 int i, j, c;
60 char *zFile = 0;
@@ -120,19 +118,19 @@
118 );
119 }
120 free(zLogin);
121 }else if( strncmp(zUrl, "ssh://", 6)==0 ){
122 char *zLogin;
123 char *zExe;
124 int i, j;
125 g.urlIsFile = 0;
126 g.urlIsSsh = 1;
127 g.urlProtocol = "ssh";
128 g.urlPort = 22;
129 g.urlDfltPort = 22;
130 g.urlPasswd = "(not-used)";
131 g.urlFossil = "fossil";
 
132 for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
133 if( c=='@' ){
134 for(j=6; j<i && zUrl[j]!=':'; j++){}
135 g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
136 dehttpize(g.urlUser);
@@ -139,25 +137,54 @@
137 if( j<i ){
138 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
139 dehttpize(g.urlPasswd);
140 }
141 for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
142 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
143 i = j;
144 zLogin = mprintf("%t@", g.urlUser);
145 }else{
146 g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
147 zLogin = mprintf("");
148 }
149 url_tolower(g.urlName);
150 g.urlHostname = g.urlName;
151 g.urlPath = mprintf(&zUrl[i+1]);
152 for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
153 if( g.urlPath[i] ){
154 g.urlPath[i] = 0;
155 i++;
156 }
157 zExe = mprintf("");
158 while( g.urlPath[i]!=0 ){
159 char *zName, *zValue;
160 zName = &g.urlPath[i];
161 zValue = zName;
162 while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
163 if( g.urlPath[i]=='=' ){
164 g.urlPath[i] = 0;
165 i++;
166 zValue = &g.urlPath[i];
167 while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
168 }
169 if( g.urlPath[i] ){
170 g.urlPath[i] = 0;
171 i++;
172 }
173 if( strcmp(zName,"fossil")==0 ){
174 g.urlFossil = zValue;
175 dehttpize(g.urlFossil);
176 zExe = mprintf("?fossil=%T", g.urlFossil);
177 }
178 }
179 dehttpize(g.urlPath);
180 g.urlCanonical = mprintf(
181 "ssh://%s%T/%T%s",
182 zLogin, g.urlName, g.urlPath, zExe
183 );
184 free(zLogin);
185 free(zExe);
186 }else if( strncmp(zUrl, "file:", 5)==0 ){
187 g.urlIsFile = 1;
188 if( zUrl[5]=='/' && zUrl[6]=='/' ){
189 i = 7;
190 }else{
@@ -205,18 +232,18 @@
232 printf("g.urlIsFile = %d\n", g.urlIsFile);
233 printf("g.urlIsHttps = %d\n", g.urlIsHttps);
234 printf("g.urlIsSsh = %d\n", g.urlIsSsh);
235 printf("g.urlProtocol = %s\n", g.urlProtocol);
236 printf("g.urlName = %s\n", g.urlName);
 
237 printf("g.urlPort = %d\n", g.urlPort);
238 printf("g.urlDfltPort = %d\n", g.urlDfltPort);
239 printf("g.urlHostname = %s\n", g.urlHostname);
240 printf("g.urlPath = %s\n", g.urlPath);
241 printf("g.urlUser = %s\n", g.urlUser);
242 printf("g.urlPasswd = %s\n", g.urlPasswd);
243 printf("g.urlCanonical = %s\n", g.urlCanonical);
244 printf("g.urlFossil = %s\n", g.urlFossil);
245 if( g.urlIsFile || g.urlIsSsh ) break;
246 if( i==0 ){
247 printf("********\n");
248 url_enable_proxy("Using proxy: ");
249 }
250

Keyboard Shortcuts

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