Fossil SCM
Merge the ssh:// sync enhancement into the trunk.
Commit
0e42cc1b77f07d00546d001f3052201cd3258e19
Parent
7503f9877998135…
11 files changed
+65
-12
+2
+5
-1
+47
+29
-3
+12
-2
+1
+5
+57
-2
+7
-2
+1
+65
-12
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -1017,10 +1017,22 @@ | ||
| 1017 | 1017 | "<html><body>Unrecognized HTTP Request</body></html>\n" |
| 1018 | 1018 | ); |
| 1019 | 1019 | cgi_reply(); |
| 1020 | 1020 | fossil_exit(0); |
| 1021 | 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 | +} | |
| 1022 | 1034 | |
| 1023 | 1035 | /* |
| 1024 | 1036 | ** Panic and die while processing a webpage. |
| 1025 | 1037 | */ |
| 1026 | 1038 | void cgi_panic(const char *zFormat, ...){ |
| @@ -1073,10 +1085,11 @@ | ||
| 1073 | 1085 | void cgi_handle_http_request(const char *zIpAddr){ |
| 1074 | 1086 | char *z, *zToken; |
| 1075 | 1087 | int i; |
| 1076 | 1088 | struct sockaddr_in remoteName; |
| 1077 | 1089 | size_t size = sizeof(struct sockaddr_in); |
| 1090 | + int accessTokenSeen = 0; | |
| 1078 | 1091 | char zLine[2000]; /* A single line of input. */ |
| 1079 | 1092 | |
| 1080 | 1093 | g.fullHttpReply = 1; |
| 1081 | 1094 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1082 | 1095 | malformed_request(); |
| @@ -1122,34 +1135,56 @@ | ||
| 1122 | 1135 | while( isspace(*zVal) ){ zVal++; } |
| 1123 | 1136 | i = strlen(zVal); |
| 1124 | 1137 | while( i>0 && isspace(zVal[i-1]) ){ i--; } |
| 1125 | 1138 | zVal[i] = 0; |
| 1126 | 1139 | for(i=0; zFieldName[i]; i++){ zFieldName[i] = tolower(zFieldName[i]); } |
| 1127 | - if( strcmp(zFieldName,"user-agent:")==0 ){ | |
| 1128 | - cgi_setenv("HTTP_USER_AGENT", zVal); | |
| 1129 | - }else if( strcmp(zFieldName,"content-length:")==0 ){ | |
| 1140 | + if( strcmp(zFieldName,"content-length:")==0 ){ | |
| 1130 | 1141 | cgi_setenv("CONTENT_LENGTH", zVal); |
| 1131 | - }else if( strcmp(zFieldName,"referer:")==0 ){ | |
| 1132 | - cgi_setenv("HTTP_REFERER", zVal); | |
| 1133 | - }else if( strcmp(zFieldName,"host:")==0 ){ | |
| 1134 | - cgi_setenv("HTTP_HOST", zVal); | |
| 1135 | 1142 | }else if( strcmp(zFieldName,"content-type:")==0 ){ |
| 1136 | 1143 | cgi_setenv("CONTENT_TYPE", zVal); |
| 1137 | 1144 | }else if( strcmp(zFieldName,"cookie:")==0 ){ |
| 1138 | 1145 | cgi_setenv("HTTP_COOKIE", zVal); |
| 1146 | + }else if( strcmp(zFieldName,"https:")==0 ){ | |
| 1147 | + cgi_setenv("HTTPS", zVal); | |
| 1148 | + }else if( strcmp(zFieldName,"host:")==0 ){ | |
| 1149 | + cgi_setenv("HTTP_HOST", zVal); | |
| 1139 | 1150 | }else if( strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1140 | 1151 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1141 | 1152 | }else if( strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1142 | 1153 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1143 | - }else if( strcmp(zFieldName,"https:")==0 ){ | |
| 1144 | - cgi_setenv("HTTPS", 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 | + cgi_setenv("HTTP_USER_AGENT", zVal); | |
| 1145 | 1166 | } |
| 1167 | +#endif | |
| 1168 | + } | |
| 1169 | + | |
| 1170 | + if( g.zAccessToken && !accessTokenSeen ){ | |
| 1171 | + forbidden_request(); | |
| 1146 | 1172 | } |
| 1147 | 1173 | |
| 1148 | 1174 | cgi_init(); |
| 1149 | 1175 | } |
| 1150 | 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 | + | |
| 1151 | 1186 | /* |
| 1152 | 1187 | ** Maximum number of child processes that we can have running |
| 1153 | 1188 | ** at one time before we start slowing things down. |
| 1154 | 1189 | */ |
| 1155 | 1190 | #define MAX_PARALLEL 2 |
| @@ -1162,11 +1197,11 @@ | ||
| 1162 | 1197 | ** The parent never returns from this procedure. |
| 1163 | 1198 | ** |
| 1164 | 1199 | ** Return 0 to each child as it runs. If unable to establish a |
| 1165 | 1200 | ** listening socket, return non-zero. |
| 1166 | 1201 | */ |
| 1167 | -int cgi_http_server(int mnPort, int mxPort, char *zBrowser){ | |
| 1202 | +int cgi_http_server(int mnPort, int mxPort, char *zBrowser, int flags){ | |
| 1168 | 1203 | #ifdef __MINGW32__ |
| 1169 | 1204 | /* Use win32_http_server() instead */ |
| 1170 | 1205 | fossil_exit(1); |
| 1171 | 1206 | #else |
| 1172 | 1207 | int listener = -1; /* The server socket */ |
| @@ -1181,11 +1216,15 @@ | ||
| 1181 | 1216 | int iPort = mnPort; |
| 1182 | 1217 | |
| 1183 | 1218 | while( iPort<=mxPort ){ |
| 1184 | 1219 | memset(&inaddr, 0, sizeof(inaddr)); |
| 1185 | 1220 | inaddr.sin_family = AF_INET; |
| 1186 | - inaddr.sin_addr.s_addr = INADDR_ANY; | |
| 1221 | + if( flags & HTTP_SERVER_LOCALHOST ){ | |
| 1222 | + inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
| 1223 | + }else{ | |
| 1224 | + inaddr.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 1225 | + } | |
| 1187 | 1226 | inaddr.sin_port = htons(iPort); |
| 1188 | 1227 | listener = socket(AF_INET, SOCK_STREAM, 0); |
| 1189 | 1228 | if( listener<0 ){ |
| 1190 | 1229 | iPort++; |
| 1191 | 1230 | continue; |
| @@ -1226,11 +1265,25 @@ | ||
| 1226 | 1265 | } |
| 1227 | 1266 | delay.tv_sec = 60; |
| 1228 | 1267 | delay.tv_usec = 0; |
| 1229 | 1268 | FD_ZERO(&readfds); |
| 1230 | 1269 | FD_SET( listener, &readfds); |
| 1231 | - if( select( listener+1, &readfds, 0, 0, &delay) ){ | |
| 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) ){ | |
| 1232 | 1285 | lenaddr = sizeof(inaddr); |
| 1233 | 1286 | connection = accept(listener, (struct sockaddr*)&inaddr, |
| 1234 | 1287 | (socklen_t*) &lenaddr); |
| 1235 | 1288 | if( connection>=0 ){ |
| 1236 | 1289 | child = fork(); |
| 1237 | 1290 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1017,10 +1017,22 @@ | |
| 1017 | "<html><body>Unrecognized HTTP Request</body></html>\n" |
| 1018 | ); |
| 1019 | cgi_reply(); |
| 1020 | fossil_exit(0); |
| 1021 | } |
| 1022 | |
| 1023 | /* |
| 1024 | ** Panic and die while processing a webpage. |
| 1025 | */ |
| 1026 | void cgi_panic(const char *zFormat, ...){ |
| @@ -1073,10 +1085,11 @@ | |
| 1073 | void cgi_handle_http_request(const char *zIpAddr){ |
| 1074 | char *z, *zToken; |
| 1075 | int i; |
| 1076 | struct sockaddr_in remoteName; |
| 1077 | size_t size = sizeof(struct sockaddr_in); |
| 1078 | char zLine[2000]; /* A single line of input. */ |
| 1079 | |
| 1080 | g.fullHttpReply = 1; |
| 1081 | if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){ |
| 1082 | malformed_request(); |
| @@ -1122,34 +1135,56 @@ | |
| 1122 | while( isspace(*zVal) ){ zVal++; } |
| 1123 | i = strlen(zVal); |
| 1124 | while( i>0 && isspace(zVal[i-1]) ){ i--; } |
| 1125 | zVal[i] = 0; |
| 1126 | for(i=0; zFieldName[i]; i++){ zFieldName[i] = tolower(zFieldName[i]); } |
| 1127 | if( strcmp(zFieldName,"user-agent:")==0 ){ |
| 1128 | cgi_setenv("HTTP_USER_AGENT", zVal); |
| 1129 | }else if( strcmp(zFieldName,"content-length:")==0 ){ |
| 1130 | cgi_setenv("CONTENT_LENGTH", zVal); |
| 1131 | }else if( strcmp(zFieldName,"referer:")==0 ){ |
| 1132 | cgi_setenv("HTTP_REFERER", zVal); |
| 1133 | }else if( strcmp(zFieldName,"host:")==0 ){ |
| 1134 | cgi_setenv("HTTP_HOST", zVal); |
| 1135 | }else if( strcmp(zFieldName,"content-type:")==0 ){ |
| 1136 | cgi_setenv("CONTENT_TYPE", zVal); |
| 1137 | }else if( strcmp(zFieldName,"cookie:")==0 ){ |
| 1138 | cgi_setenv("HTTP_COOKIE", zVal); |
| 1139 | }else if( strcmp(zFieldName,"if-none-match:")==0 ){ |
| 1140 | cgi_setenv("HTTP_IF_NONE_MATCH", zVal); |
| 1141 | }else if( strcmp(zFieldName,"if-modified-since:")==0 ){ |
| 1142 | cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal); |
| 1143 | }else if( strcmp(zFieldName,"https:")==0 ){ |
| 1144 | cgi_setenv("HTTPS", zVal); |
| 1145 | } |
| 1146 | } |
| 1147 | |
| 1148 | cgi_init(); |
| 1149 | } |
| 1150 | |
| 1151 | /* |
| 1152 | ** Maximum number of child processes that we can have running |
| 1153 | ** at one time before we start slowing things down. |
| 1154 | */ |
| 1155 | #define MAX_PARALLEL 2 |
| @@ -1162,11 +1197,11 @@ | |
| 1162 | ** The parent never returns from this procedure. |
| 1163 | ** |
| 1164 | ** Return 0 to each child as it runs. If unable to establish a |
| 1165 | ** listening socket, return non-zero. |
| 1166 | */ |
| 1167 | int cgi_http_server(int mnPort, int mxPort, char *zBrowser){ |
| 1168 | #ifdef __MINGW32__ |
| 1169 | /* Use win32_http_server() instead */ |
| 1170 | fossil_exit(1); |
| 1171 | #else |
| 1172 | int listener = -1; /* The server socket */ |
| @@ -1181,11 +1216,15 @@ | |
| 1181 | int iPort = mnPort; |
| 1182 | |
| 1183 | while( iPort<=mxPort ){ |
| 1184 | memset(&inaddr, 0, sizeof(inaddr)); |
| 1185 | inaddr.sin_family = AF_INET; |
| 1186 | inaddr.sin_addr.s_addr = INADDR_ANY; |
| 1187 | inaddr.sin_port = htons(iPort); |
| 1188 | listener = socket(AF_INET, SOCK_STREAM, 0); |
| 1189 | if( listener<0 ){ |
| 1190 | iPort++; |
| 1191 | continue; |
| @@ -1226,11 +1265,25 @@ | |
| 1226 | } |
| 1227 | delay.tv_sec = 60; |
| 1228 | delay.tv_usec = 0; |
| 1229 | FD_ZERO(&readfds); |
| 1230 | FD_SET( listener, &readfds); |
| 1231 | if( select( listener+1, &readfds, 0, 0, &delay) ){ |
| 1232 | lenaddr = sizeof(inaddr); |
| 1233 | connection = accept(listener, (struct sockaddr*)&inaddr, |
| 1234 | (socklen_t*) &lenaddr); |
| 1235 | if( connection>=0 ){ |
| 1236 | child = fork(); |
| 1237 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -1017,10 +1017,22 @@ | |
| 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 | /* |
| 1036 | ** Panic and die while processing a webpage. |
| 1037 | */ |
| 1038 | void cgi_panic(const char *zFormat, ...){ |
| @@ -1073,10 +1085,11 @@ | |
| 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(); |
| @@ -1122,34 +1135,56 @@ | |
| 1135 | while( isspace(*zVal) ){ zVal++; } |
| 1136 | i = strlen(zVal); |
| 1137 | while( i>0 && isspace(zVal[i-1]) ){ i--; } |
| 1138 | zVal[i] = 0; |
| 1139 | for(i=0; zFieldName[i]; i++){ zFieldName[i] = tolower(zFieldName[i]); } |
| 1140 | if( strcmp(zFieldName,"content-length:")==0 ){ |
| 1141 | cgi_setenv("CONTENT_LENGTH", zVal); |
| 1142 | }else if( strcmp(zFieldName,"content-type:")==0 ){ |
| 1143 | cgi_setenv("CONTENT_TYPE", zVal); |
| 1144 | }else if( strcmp(zFieldName,"cookie:")==0 ){ |
| 1145 | cgi_setenv("HTTP_COOKIE", zVal); |
| 1146 | }else if( strcmp(zFieldName,"https:")==0 ){ |
| 1147 | cgi_setenv("HTTPS", zVal); |
| 1148 | }else if( strcmp(zFieldName,"host:")==0 ){ |
| 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 | 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 |
| 1188 | ** at one time before we start slowing things down. |
| 1189 | */ |
| 1190 | #define MAX_PARALLEL 2 |
| @@ -1162,11 +1197,11 @@ | |
| 1197 | ** The parent never returns from this procedure. |
| 1198 | ** |
| 1199 | ** Return 0 to each child as it runs. If unable to establish a |
| 1200 | ** listening socket, return non-zero. |
| 1201 | */ |
| 1202 | int cgi_http_server(int mnPort, int mxPort, char *zBrowser, int flags){ |
| 1203 | #ifdef __MINGW32__ |
| 1204 | /* Use win32_http_server() instead */ |
| 1205 | fossil_exit(1); |
| 1206 | #else |
| 1207 | int listener = -1; /* The server socket */ |
| @@ -1181,11 +1216,15 @@ | |
| 1216 | int iPort = mnPort; |
| 1217 | |
| 1218 | while( iPort<=mxPort ){ |
| 1219 | memset(&inaddr, 0, sizeof(inaddr)); |
| 1220 | inaddr.sin_family = AF_INET; |
| 1221 | if( flags & HTTP_SERVER_LOCALHOST ){ |
| 1222 | inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 1223 | }else{ |
| 1224 | inaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 1225 | } |
| 1226 | inaddr.sin_port = htons(iPort); |
| 1227 | listener = socket(AF_INET, SOCK_STREAM, 0); |
| 1228 | if( listener<0 ){ |
| 1229 | iPort++; |
| 1230 | continue; |
| @@ -1226,11 +1265,25 @@ | |
| 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 | child = fork(); |
| 1290 |
+2
| --- src/config.h | ||
| +++ src/config.h | ||
| @@ -29,10 +29,12 @@ | ||
| 29 | 29 | #include <stdarg.h> |
| 30 | 30 | #include <assert.h> |
| 31 | 31 | #ifdef __MINGW32__ |
| 32 | 32 | # include <windows.h> |
| 33 | 33 | #else |
| 34 | +# include <sys/types.h> | |
| 35 | +# include <signal.h> | |
| 34 | 36 | # include <pwd.h> |
| 35 | 37 | #endif |
| 36 | 38 | |
| 37 | 39 | #include "sqlite3.h" |
| 38 | 40 | |
| 39 | 41 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -29,10 +29,12 @@ | |
| 29 | #include <stdarg.h> |
| 30 | #include <assert.h> |
| 31 | #ifdef __MINGW32__ |
| 32 | # include <windows.h> |
| 33 | #else |
| 34 | # include <pwd.h> |
| 35 | #endif |
| 36 | |
| 37 | #include "sqlite3.h" |
| 38 | |
| 39 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -29,10 +29,12 @@ | |
| 29 | #include <stdarg.h> |
| 30 | #include <assert.h> |
| 31 | #ifdef __MINGW32__ |
| 32 | # include <windows.h> |
| 33 | #else |
| 34 | # include <sys/types.h> |
| 35 | # include <signal.h> |
| 36 | # include <pwd.h> |
| 37 | #endif |
| 38 | |
| 39 | #include "sqlite3.h" |
| 40 | |
| 41 |
+5
-1
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -111,11 +111,15 @@ | ||
| 111 | 111 | if( g.fHttpTrace ){ |
| 112 | 112 | blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 113 | 113 | }else{ |
| 114 | 114 | blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n"); |
| 115 | 115 | } |
| 116 | - blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload)); | |
| 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"); | |
| 117 | 121 | } |
| 118 | 122 | |
| 119 | 123 | /* |
| 120 | 124 | ** Sign the content in pSend, compress it, and send it to the server |
| 121 | 125 | ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply |
| 122 | 126 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -111,11 +111,15 @@ | |
| 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\r\n", blob_size(pPayload)); |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | ** Sign the content in pSend, compress it, and send it to the server |
| 121 | ** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply |
| 122 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -111,11 +111,15 @@ | |
| 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 |
| 126 |
+47
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -63,10 +63,51 @@ | ||
| 63 | 63 | if( resetFlag ){ |
| 64 | 64 | transport.nSent = 0; |
| 65 | 65 | transport.nRcvd = 0; |
| 66 | 66 | } |
| 67 | 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 | +} | |
| 68 | 109 | |
| 69 | 110 | /* |
| 70 | 111 | ** Open a connection to the server. The server is defined by the following |
| 71 | 112 | ** global variables: |
| 72 | 113 | ** |
| @@ -313,13 +354,19 @@ | ||
| 313 | 354 | /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */ |
| 314 | 355 | return &transport.pBuf[iStart]; |
| 315 | 356 | } |
| 316 | 357 | |
| 317 | 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 | + } | |
| 318 | 365 | if( g.urlIsHttps ){ |
| 319 | 366 | #ifdef FOSSIL_ENABLE_SSL |
| 320 | 367 | ssl_global_shutdown(); |
| 321 | 368 | #endif |
| 322 | 369 | }else{ |
| 323 | 370 | socket_global_shutdown(); |
| 324 | 371 | } |
| 325 | 372 | } |
| 326 | 373 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -63,10 +63,51 @@ | |
| 63 | if( resetFlag ){ |
| 64 | transport.nSent = 0; |
| 65 | transport.nRcvd = 0; |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | /* |
| 70 | ** Open a connection to the server. The server is defined by the following |
| 71 | ** global variables: |
| 72 | ** |
| @@ -313,13 +354,19 @@ | |
| 313 | /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */ |
| 314 | return &transport.pBuf[iStart]; |
| 315 | } |
| 316 | |
| 317 | void transport_global_shutdown(void){ |
| 318 | if( g.urlIsHttps ){ |
| 319 | #ifdef FOSSIL_ENABLE_SSL |
| 320 | ssl_global_shutdown(); |
| 321 | #endif |
| 322 | }else{ |
| 323 | socket_global_shutdown(); |
| 324 | } |
| 325 | } |
| 326 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -63,10 +63,51 @@ | |
| 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 |
| 112 | ** global variables: |
| 113 | ** |
| @@ -313,13 +354,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 |
+29
-3
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -83,18 +83,25 @@ | ||
| 83 | 83 | FILE *httpOut; /* Send HTTP output here */ |
| 84 | 84 | int xlinkClusterOnly; /* Set when cloning. Only process clusters */ |
| 85 | 85 | int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ |
| 86 | 86 | int *aCommitFile; /* Array of files to be committed */ |
| 87 | 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 */ | |
| 88 | 92 | |
| 89 | 93 | int urlIsFile; /* True if a "file:" url */ |
| 90 | 94 | int urlIsHttps; /* True if a "https:" url */ |
| 95 | + int urlIsSsh; /* True if an "ssh:" url */ | |
| 91 | 96 | char *urlName; /* Hostname for http: or filename for file: */ |
| 97 | + char *urlSshHost; /* Hostname for ssh: tunnels */ | |
| 92 | 98 | char *urlHostname; /* The HOST: parameter on http headers */ |
| 93 | 99 | char *urlProtocol; /* "http" or "https" */ |
| 94 | 100 | int urlPort; /* TCP port number for http: or https: */ |
| 95 | 101 | int urlDfltPort; /* The default port for the given protocol */ |
| 102 | + int urlSshPort; /* TCP port for SSH */ | |
| 96 | 103 | char *urlPath; /* Pathname for http: */ |
| 97 | 104 | char *urlUser; /* User id for http: */ |
| 98 | 105 | char *urlPasswd; /* Password for http: */ |
| 99 | 106 | char *urlCanonical; /* Canonical representation of the URL */ |
| 100 | 107 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| @@ -969,10 +976,11 @@ | ||
| 969 | 976 | } |
| 970 | 977 | #endif |
| 971 | 978 | #endif |
| 972 | 979 | |
| 973 | 980 | /* |
| 981 | +** COMMAND: sshd | |
| 974 | 982 | ** COMMAND: server |
| 975 | 983 | ** COMMAND: ui |
| 976 | 984 | ** |
| 977 | 985 | ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY? |
| 978 | 986 | ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY? |
| @@ -982,24 +990,29 @@ | ||
| 982 | 990 | ** --port option. The optional argument is the name of the repository. |
| 983 | 991 | ** The repository argument may be omitted if the working directory is |
| 984 | 992 | ** within an open checkout. |
| 985 | 993 | ** |
| 986 | 994 | ** The "ui" command automatically starts a web browser after initializing |
| 987 | -** the web server. | |
| 995 | +** the web server. The "ui" command also binds to 127.0.0.1 and so will | |
| 996 | +** only process HTTP traffic from the local machine. | |
| 988 | 997 | ** |
| 989 | 998 | ** In the "server" command, the REPOSITORY can be a directory (aka folder) |
| 990 | 999 | ** that contains one or more respositories with names ending in ".fossil". |
| 991 | 1000 | ** In that case, the first element of the URL is used to select among the |
| 992 | 1001 | ** various repositories. |
| 1002 | +** | |
| 1003 | +** The "ui" or "server" verb can also be "sshd". This is used internally | |
| 1004 | +** by the ssh:// sync method. | |
| 993 | 1005 | */ |
| 994 | 1006 | void cmd_webserver(void){ |
| 995 | 1007 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 996 | 1008 | const char *zPort; /* Value of the --port option */ |
| 997 | 1009 | char *zBrowser; /* Name of web browser program */ |
| 998 | 1010 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 999 | 1011 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1000 | 1012 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1013 | + int flags = 0; /* Server flags */ | |
| 1001 | 1014 | |
| 1002 | 1015 | #ifdef __MINGW32__ |
| 1003 | 1016 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 1004 | 1017 | zStopperFile = find_option("stopper", 0, 1); |
| 1005 | 1018 | #endif |
| @@ -1010,17 +1023,30 @@ | ||
| 1010 | 1023 | } |
| 1011 | 1024 | zPort = find_option("port", "P", 1); |
| 1012 | 1025 | zNotFound = find_option("notfound", 0, 1); |
| 1013 | 1026 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 1014 | 1027 | isUiCmd = g.argv[1][0]=='u'; |
| 1028 | + if( isUiCmd ) flags |= HTTP_SERVER_LOCALHOST; | |
| 1015 | 1029 | find_server_repository(isUiCmd); |
| 1016 | 1030 | if( zPort ){ |
| 1017 | 1031 | iPort = mxPort = atoi(zPort); |
| 1018 | 1032 | }else{ |
| 1019 | 1033 | iPort = db_get_int("http-port", 8080); |
| 1020 | 1034 | mxPort = iPort+100; |
| 1021 | 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 | + } | |
| 1022 | 1048 | #ifndef __MINGW32__ |
| 1023 | 1049 | /* Unix implementation */ |
| 1024 | 1050 | if( isUiCmd ){ |
| 1025 | 1051 | #if !defined(__DARWIN__) && !defined(__APPLE__) |
| 1026 | 1052 | zBrowser = db_get("web-browser", 0); |
| @@ -1039,11 +1065,11 @@ | ||
| 1039 | 1065 | zBrowser = db_get("web-browser", "open"); |
| 1040 | 1066 | #endif |
| 1041 | 1067 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 1042 | 1068 | } |
| 1043 | 1069 | db_close(); |
| 1044 | - if( cgi_http_server(iPort, mxPort, zBrowserCmd) ){ | |
| 1070 | + if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){ | |
| 1045 | 1071 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 1046 | 1072 | } |
| 1047 | 1073 | g.httpIn = stdin; |
| 1048 | 1074 | g.httpOut = stdout; |
| 1049 | 1075 | if( g.fHttpTrace || g.fSqlTrace ){ |
| @@ -1059,8 +1085,8 @@ | ||
| 1059 | 1085 | if( isUiCmd ){ |
| 1060 | 1086 | zBrowser = db_get("web-browser", "start"); |
| 1061 | 1087 | zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser); |
| 1062 | 1088 | } |
| 1063 | 1089 | db_close(); |
| 1064 | - win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound); | |
| 1090 | + win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound, flags); | |
| 1065 | 1091 | #endif |
| 1066 | 1092 | } |
| 1067 | 1093 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -83,18 +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 | char *urlName; /* Hostname for http: or filename for file: */ |
| 92 | char *urlHostname; /* The HOST: parameter on http headers */ |
| 93 | char *urlProtocol; /* "http" or "https" */ |
| 94 | int urlPort; /* TCP port number for http: or https: */ |
| 95 | int urlDfltPort; /* The default port for the given protocol */ |
| 96 | char *urlPath; /* Pathname for http: */ |
| 97 | char *urlUser; /* User id for http: */ |
| 98 | char *urlPasswd; /* Password for http: */ |
| 99 | char *urlCanonical; /* Canonical representation of the URL */ |
| 100 | char *urlProxyAuth; /* Proxy-Authorizer: string */ |
| @@ -969,10 +976,11 @@ | |
| 969 | } |
| 970 | #endif |
| 971 | #endif |
| 972 | |
| 973 | /* |
| 974 | ** COMMAND: server |
| 975 | ** COMMAND: ui |
| 976 | ** |
| 977 | ** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY? |
| 978 | ** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY? |
| @@ -982,24 +990,29 @@ | |
| 982 | ** --port option. The optional argument is the name of the repository. |
| 983 | ** The repository argument may be omitted if the working directory is |
| 984 | ** within an open checkout. |
| 985 | ** |
| 986 | ** The "ui" command automatically starts a web browser after initializing |
| 987 | ** the web server. |
| 988 | ** |
| 989 | ** In the "server" command, the REPOSITORY can be a directory (aka folder) |
| 990 | ** that contains one or more respositories with names ending in ".fossil". |
| 991 | ** In that case, the first element of the URL is used to select among the |
| 992 | ** various repositories. |
| 993 | */ |
| 994 | void cmd_webserver(void){ |
| 995 | int iPort, mxPort; /* Range of TCP ports allowed */ |
| 996 | const char *zPort; /* Value of the --port option */ |
| 997 | char *zBrowser; /* Name of web browser program */ |
| 998 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 999 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1000 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1001 | |
| 1002 | #ifdef __MINGW32__ |
| 1003 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 1004 | zStopperFile = find_option("stopper", 0, 1); |
| 1005 | #endif |
| @@ -1010,17 +1023,30 @@ | |
| 1010 | } |
| 1011 | zPort = find_option("port", "P", 1); |
| 1012 | zNotFound = find_option("notfound", 0, 1); |
| 1013 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 1014 | isUiCmd = g.argv[1][0]=='u'; |
| 1015 | find_server_repository(isUiCmd); |
| 1016 | if( zPort ){ |
| 1017 | iPort = mxPort = atoi(zPort); |
| 1018 | }else{ |
| 1019 | iPort = db_get_int("http-port", 8080); |
| 1020 | mxPort = iPort+100; |
| 1021 | } |
| 1022 | #ifndef __MINGW32__ |
| 1023 | /* Unix implementation */ |
| 1024 | if( isUiCmd ){ |
| 1025 | #if !defined(__DARWIN__) && !defined(__APPLE__) |
| 1026 | zBrowser = db_get("web-browser", 0); |
| @@ -1039,11 +1065,11 @@ | |
| 1039 | zBrowser = db_get("web-browser", "open"); |
| 1040 | #endif |
| 1041 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 1042 | } |
| 1043 | db_close(); |
| 1044 | if( cgi_http_server(iPort, mxPort, zBrowserCmd) ){ |
| 1045 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 1046 | } |
| 1047 | g.httpIn = stdin; |
| 1048 | g.httpOut = stdout; |
| 1049 | if( g.fHttpTrace || g.fSqlTrace ){ |
| @@ -1059,8 +1085,8 @@ | |
| 1059 | if( isUiCmd ){ |
| 1060 | zBrowser = db_get("web-browser", "start"); |
| 1061 | zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser); |
| 1062 | } |
| 1063 | db_close(); |
| 1064 | win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound); |
| 1065 | #endif |
| 1066 | } |
| 1067 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -83,18 +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 */ |
| @@ -969,10 +976,11 @@ | |
| 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? |
| @@ -982,24 +990,29 @@ | |
| 990 | ** --port option. The optional argument is the name of the repository. |
| 991 | ** The repository argument may be omitted if the working directory is |
| 992 | ** within an open checkout. |
| 993 | ** |
| 994 | ** The "ui" command automatically starts a web browser after initializing |
| 995 | ** the web server. The "ui" command also binds to 127.0.0.1 and so will |
| 996 | ** only process HTTP traffic from the local machine. |
| 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 */ |
| 1010 | char *zBrowserCmd = 0; /* Command to launch the web browser */ |
| 1011 | int isUiCmd; /* True if command is "ui", not "server' */ |
| 1012 | const char *zNotFound; /* The --notfound option or NULL */ |
| 1013 | int flags = 0; /* Server flags */ |
| 1014 | |
| 1015 | #ifdef __MINGW32__ |
| 1016 | const char *zStopperFile; /* Name of file used to terminate server */ |
| 1017 | zStopperFile = find_option("stopper", 0, 1); |
| 1018 | #endif |
| @@ -1010,17 +1023,30 @@ | |
| 1023 | } |
| 1024 | zPort = find_option("port", "P", 1); |
| 1025 | zNotFound = find_option("notfound", 0, 1); |
| 1026 | if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?"); |
| 1027 | isUiCmd = g.argv[1][0]=='u'; |
| 1028 | if( isUiCmd ) flags |= HTTP_SERVER_LOCALHOST; |
| 1029 | find_server_repository(isUiCmd); |
| 1030 | if( zPort ){ |
| 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); |
| @@ -1039,11 +1065,11 @@ | |
| 1065 | zBrowser = db_get("web-browser", "open"); |
| 1066 | #endif |
| 1067 | zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser); |
| 1068 | } |
| 1069 | db_close(); |
| 1070 | if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){ |
| 1071 | fossil_fatal("unable to listen on TCP socket %d", iPort); |
| 1072 | } |
| 1073 | g.httpIn = stdin; |
| 1074 | g.httpOut = stdout; |
| 1075 | if( g.fHttpTrace || g.fSqlTrace ){ |
| @@ -1059,8 +1085,8 @@ | |
| 1085 | if( isUiCmd ){ |
| 1086 | zBrowser = db_get("web-browser", "start"); |
| 1087 | zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser); |
| 1088 | } |
| 1089 | db_close(); |
| 1090 | win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound, flags); |
| 1091 | #endif |
| 1092 | } |
| 1093 |
+12
-2
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -51,10 +51,11 @@ | ||
| 51 | 51 | $(SRCDIR)/md5.c \ |
| 52 | 52 | $(SRCDIR)/merge.c \ |
| 53 | 53 | $(SRCDIR)/merge3.c \ |
| 54 | 54 | $(SRCDIR)/name.c \ |
| 55 | 55 | $(SRCDIR)/pivot.c \ |
| 56 | + $(SRCDIR)/popen.c \ | |
| 56 | 57 | $(SRCDIR)/pqueue.c \ |
| 57 | 58 | $(SRCDIR)/printf.c \ |
| 58 | 59 | $(SRCDIR)/rebuild.c \ |
| 59 | 60 | $(SRCDIR)/report.c \ |
| 60 | 61 | $(SRCDIR)/rss.c \ |
| @@ -123,10 +124,11 @@ | ||
| 123 | 124 | md5_.c \ |
| 124 | 125 | merge_.c \ |
| 125 | 126 | merge3_.c \ |
| 126 | 127 | name_.c \ |
| 127 | 128 | pivot_.c \ |
| 129 | + popen_.c \ | |
| 128 | 130 | pqueue_.c \ |
| 129 | 131 | printf_.c \ |
| 130 | 132 | rebuild_.c \ |
| 131 | 133 | report_.c \ |
| 132 | 134 | rss_.c \ |
| @@ -195,10 +197,11 @@ | ||
| 195 | 197 | $(OBJDIR)/md5.o \ |
| 196 | 198 | $(OBJDIR)/merge.o \ |
| 197 | 199 | $(OBJDIR)/merge3.o \ |
| 198 | 200 | $(OBJDIR)/name.o \ |
| 199 | 201 | $(OBJDIR)/pivot.o \ |
| 202 | + $(OBJDIR)/popen.o \ | |
| 200 | 203 | $(OBJDIR)/pqueue.o \ |
| 201 | 204 | $(OBJDIR)/printf.o \ |
| 202 | 205 | $(OBJDIR)/rebuild.o \ |
| 203 | 206 | $(OBJDIR)/report.o \ |
| 204 | 207 | $(OBJDIR)/rss.o \ |
| @@ -270,16 +273,16 @@ | ||
| 270 | 273 | # noop |
| 271 | 274 | |
| 272 | 275 | clean: |
| 273 | 276 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 274 | 277 | rm -f translate makeheaders mkindex page_index.h headers |
| 275 | - rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h | |
| 278 | + rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h popen.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h | |
| 276 | 279 | |
| 277 | 280 | page_index.h: $(TRANS_SRC) mkindex |
| 278 | 281 | ./mkindex $(TRANS_SRC) >$@ |
| 279 | 282 | headers: page_index.h makeheaders VERSION.h |
| 280 | - ./makeheaders add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h | |
| 283 | + ./makeheaders add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h | |
| 281 | 284 | touch headers |
| 282 | 285 | headers: Makefile |
| 283 | 286 | Makefile: |
| 284 | 287 | add_.c: $(SRCDIR)/add.c translate |
| 285 | 288 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -559,10 +562,17 @@ | ||
| 559 | 562 | |
| 560 | 563 | $(OBJDIR)/pivot.o: pivot_.c pivot.h $(SRCDIR)/config.h |
| 561 | 564 | $(XTCC) -o $(OBJDIR)/pivot.o -c pivot_.c |
| 562 | 565 | |
| 563 | 566 | pivot.h: headers |
| 567 | +popen_.c: $(SRCDIR)/popen.c translate | |
| 568 | + ./translate $(SRCDIR)/popen.c >popen_.c | |
| 569 | + | |
| 570 | +$(OBJDIR)/popen.o: popen_.c popen.h $(SRCDIR)/config.h | |
| 571 | + $(XTCC) -o $(OBJDIR)/popen.o -c popen_.c | |
| 572 | + | |
| 573 | +popen.h: headers | |
| 564 | 574 | pqueue_.c: $(SRCDIR)/pqueue.c translate |
| 565 | 575 | ./translate $(SRCDIR)/pqueue.c >pqueue_.c |
| 566 | 576 | |
| 567 | 577 | $(OBJDIR)/pqueue.o: pqueue_.c pqueue.h $(SRCDIR)/config.h |
| 568 | 578 | $(XTCC) -o $(OBJDIR)/pqueue.o -c pqueue_.c |
| 569 | 579 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -51,10 +51,11 @@ | |
| 51 | $(SRCDIR)/md5.c \ |
| 52 | $(SRCDIR)/merge.c \ |
| 53 | $(SRCDIR)/merge3.c \ |
| 54 | $(SRCDIR)/name.c \ |
| 55 | $(SRCDIR)/pivot.c \ |
| 56 | $(SRCDIR)/pqueue.c \ |
| 57 | $(SRCDIR)/printf.c \ |
| 58 | $(SRCDIR)/rebuild.c \ |
| 59 | $(SRCDIR)/report.c \ |
| 60 | $(SRCDIR)/rss.c \ |
| @@ -123,10 +124,11 @@ | |
| 123 | md5_.c \ |
| 124 | merge_.c \ |
| 125 | merge3_.c \ |
| 126 | name_.c \ |
| 127 | pivot_.c \ |
| 128 | pqueue_.c \ |
| 129 | printf_.c \ |
| 130 | rebuild_.c \ |
| 131 | report_.c \ |
| 132 | rss_.c \ |
| @@ -195,10 +197,11 @@ | |
| 195 | $(OBJDIR)/md5.o \ |
| 196 | $(OBJDIR)/merge.o \ |
| 197 | $(OBJDIR)/merge3.o \ |
| 198 | $(OBJDIR)/name.o \ |
| 199 | $(OBJDIR)/pivot.o \ |
| 200 | $(OBJDIR)/pqueue.o \ |
| 201 | $(OBJDIR)/printf.o \ |
| 202 | $(OBJDIR)/rebuild.o \ |
| 203 | $(OBJDIR)/report.o \ |
| 204 | $(OBJDIR)/rss.o \ |
| @@ -270,16 +273,16 @@ | |
| 270 | # noop |
| 271 | |
| 272 | clean: |
| 273 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 274 | rm -f translate makeheaders mkindex page_index.h headers |
| 275 | rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h |
| 276 | |
| 277 | page_index.h: $(TRANS_SRC) mkindex |
| 278 | ./mkindex $(TRANS_SRC) >$@ |
| 279 | headers: page_index.h makeheaders VERSION.h |
| 280 | ./makeheaders add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h |
| 281 | touch headers |
| 282 | headers: Makefile |
| 283 | Makefile: |
| 284 | add_.c: $(SRCDIR)/add.c translate |
| 285 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -559,10 +562,17 @@ | |
| 559 | |
| 560 | $(OBJDIR)/pivot.o: pivot_.c pivot.h $(SRCDIR)/config.h |
| 561 | $(XTCC) -o $(OBJDIR)/pivot.o -c pivot_.c |
| 562 | |
| 563 | pivot.h: headers |
| 564 | pqueue_.c: $(SRCDIR)/pqueue.c translate |
| 565 | ./translate $(SRCDIR)/pqueue.c >pqueue_.c |
| 566 | |
| 567 | $(OBJDIR)/pqueue.o: pqueue_.c pqueue.h $(SRCDIR)/config.h |
| 568 | $(XTCC) -o $(OBJDIR)/pqueue.o -c pqueue_.c |
| 569 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -51,10 +51,11 @@ | |
| 51 | $(SRCDIR)/md5.c \ |
| 52 | $(SRCDIR)/merge.c \ |
| 53 | $(SRCDIR)/merge3.c \ |
| 54 | $(SRCDIR)/name.c \ |
| 55 | $(SRCDIR)/pivot.c \ |
| 56 | $(SRCDIR)/popen.c \ |
| 57 | $(SRCDIR)/pqueue.c \ |
| 58 | $(SRCDIR)/printf.c \ |
| 59 | $(SRCDIR)/rebuild.c \ |
| 60 | $(SRCDIR)/report.c \ |
| 61 | $(SRCDIR)/rss.c \ |
| @@ -123,10 +124,11 @@ | |
| 124 | md5_.c \ |
| 125 | merge_.c \ |
| 126 | merge3_.c \ |
| 127 | name_.c \ |
| 128 | pivot_.c \ |
| 129 | popen_.c \ |
| 130 | pqueue_.c \ |
| 131 | printf_.c \ |
| 132 | rebuild_.c \ |
| 133 | report_.c \ |
| 134 | rss_.c \ |
| @@ -195,10 +197,11 @@ | |
| 197 | $(OBJDIR)/md5.o \ |
| 198 | $(OBJDIR)/merge.o \ |
| 199 | $(OBJDIR)/merge3.o \ |
| 200 | $(OBJDIR)/name.o \ |
| 201 | $(OBJDIR)/pivot.o \ |
| 202 | $(OBJDIR)/popen.o \ |
| 203 | $(OBJDIR)/pqueue.o \ |
| 204 | $(OBJDIR)/printf.o \ |
| 205 | $(OBJDIR)/rebuild.o \ |
| 206 | $(OBJDIR)/report.o \ |
| 207 | $(OBJDIR)/rss.o \ |
| @@ -270,16 +273,16 @@ | |
| 273 | # noop |
| 274 | |
| 275 | clean: |
| 276 | rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h |
| 277 | rm -f translate makeheaders mkindex page_index.h headers |
| 278 | rm -f add.h allrepo.h attach.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h graph.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h popen.h pqueue.h printf.h rebuild.h report.h rss.h schema.h search.h setup.h sha1.h shun.h skins.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h |
| 279 | |
| 280 | page_index.h: $(TRANS_SRC) mkindex |
| 281 | ./mkindex $(TRANS_SRC) >$@ |
| 282 | headers: page_index.h makeheaders VERSION.h |
| 283 | ./makeheaders add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h |
| 284 | touch headers |
| 285 | headers: Makefile |
| 286 | Makefile: |
| 287 | add_.c: $(SRCDIR)/add.c translate |
| 288 | ./translate $(SRCDIR)/add.c >add_.c |
| @@ -559,10 +562,17 @@ | |
| 562 | |
| 563 | $(OBJDIR)/pivot.o: pivot_.c pivot.h $(SRCDIR)/config.h |
| 564 | $(XTCC) -o $(OBJDIR)/pivot.o -c pivot_.c |
| 565 | |
| 566 | pivot.h: headers |
| 567 | popen_.c: $(SRCDIR)/popen.c translate |
| 568 | ./translate $(SRCDIR)/popen.c >popen_.c |
| 569 | |
| 570 | $(OBJDIR)/popen.o: popen_.c popen.h $(SRCDIR)/config.h |
| 571 | $(XTCC) -o $(OBJDIR)/popen.o -c popen_.c |
| 572 | |
| 573 | popen.h: headers |
| 574 | pqueue_.c: $(SRCDIR)/pqueue.c translate |
| 575 | ./translate $(SRCDIR)/pqueue.c >pqueue_.c |
| 576 | |
| 577 | $(OBJDIR)/pqueue.o: pqueue_.c pqueue.h $(SRCDIR)/config.h |
| 578 | $(XTCC) -o $(OBJDIR)/pqueue.o -c pqueue_.c |
| 579 |
+1
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -44,10 +44,11 @@ | ||
| 44 | 44 | md5 |
| 45 | 45 | merge |
| 46 | 46 | merge3 |
| 47 | 47 | name |
| 48 | 48 | pivot |
| 49 | + popen | |
| 49 | 50 | pqueue |
| 50 | 51 | printf |
| 51 | 52 | rebuild |
| 52 | 53 | report |
| 53 | 54 | rss |
| 54 | 55 | |
| 55 | 56 | ADDED src/popen.c |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -44,10 +44,11 @@ | |
| 44 | md5 |
| 45 | merge |
| 46 | merge3 |
| 47 | name |
| 48 | pivot |
| 49 | pqueue |
| 50 | printf |
| 51 | rebuild |
| 52 | report |
| 53 | rss |
| 54 | |
| 55 | DDED src/popen.c |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -44,10 +44,11 @@ | |
| 44 | md5 |
| 45 | merge |
| 46 | merge3 |
| 47 | name |
| 48 | pivot |
| 49 | popen |
| 50 | pqueue |
| 51 | printf |
| 52 | rebuild |
| 53 | report |
| 54 | rss |
| 55 | |
| 56 | DDED src/popen.c |
+5
| --- a/src/popen.c | ||
| +++ b/src/popen.c | ||
| @@ -0,0 +1,5 @@ | ||
| 1 | +TCHAR *zCmd, mb(c)zCmd), | |
| 2 | +wchar_t charTCHAR *zCmd, mb(c)zCmd), | |
| 3 | +wchar_t TCHAoutkill(childPid, SIGINT);#endif | |
| 4 | +} | |
| 5 | +return 1; on windows, yet */FILE **ppppIn = fdopen(pin[0], "r"FILE *pfclose(p |
| --- a/src/popen.c | |
| +++ b/src/popen.c | |
| @@ -0,0 +1,5 @@ | |
| --- a/src/popen.c | |
| +++ b/src/popen.c | |
| @@ -0,0 +1,5 @@ | |
| 1 | TCHAR *zCmd, mb(c)zCmd), |
| 2 | wchar_t charTCHAR *zCmd, mb(c)zCmd), |
| 3 | wchar_t TCHAoutkill(childPid, SIGINT);#endif |
| 4 | } |
| 5 | return 1; on windows, yet */FILE **ppppIn = fdopen(pin[0], "r"FILE *pfclose(p |
+57
-2
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -17,20 +17,33 @@ | ||
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code for parsing URLs that appear on the command-line |
| 19 | 19 | */ |
| 20 | 20 | #include "config.h" |
| 21 | 21 | #include "url.h" |
| 22 | + | |
| 23 | +/* | |
| 24 | +** Convert a string to lower-case. | |
| 25 | +*/ | |
| 26 | +static void url_tolower(char *z){ | |
| 27 | + while( *z ){ | |
| 28 | + *z = tolower(*z); | |
| 29 | + z++; | |
| 30 | + } | |
| 31 | +} | |
| 22 | 32 | |
| 23 | 33 | /* |
| 24 | 34 | ** Parse the given URL. Populate variables in the global "g" structure. |
| 25 | 35 | ** |
| 26 | 36 | ** g.urlIsFile True if FILE: |
| 27 | 37 | ** g.urlIsHttps True if HTTPS: |
| 38 | +** g.urlIsSsh True if SSH: | |
| 28 | 39 | ** g.urlProtocol "http" or "https" or "file" |
| 29 | 40 | ** g.urlName Hostname for HTTP: or HTTPS:. Filename for FILE: |
| 41 | +** g.urlSshHost Hostname for SSH: tunnel | |
| 30 | 42 | ** g.urlPort TCP port number for HTTP or HTTPS. |
| 31 | 43 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 44 | +** g.urlSshPort TCP port for SSH: tunnel | |
| 32 | 45 | ** g.urlPath Path name for HTTP or HTTPS. |
| 33 | 46 | ** g.urlUser Userid. |
| 34 | 47 | ** g.urlPasswd Password. |
| 35 | 48 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 36 | 49 | ** g.urlCanonical The URL in canonical form, omitting the password |
| @@ -37,10 +50,14 @@ | ||
| 37 | 50 | ** |
| 38 | 51 | ** HTTP url format is: |
| 39 | 52 | ** |
| 40 | 53 | ** http://userid:password@host:port/path?query#fragment |
| 41 | 54 | ** |
| 55 | +** SSH url format is: | |
| 56 | +** | |
| 57 | +** ssh://userid@host:port/fullpath | |
| 58 | +** | |
| 42 | 59 | */ |
| 43 | 60 | void url_parse(const char *zUrl){ |
| 44 | 61 | int i, j, c; |
| 45 | 62 | char *zFile = 0; |
| 46 | 63 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| @@ -70,15 +87,14 @@ | ||
| 70 | 87 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 71 | 88 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 72 | 89 | i = j; |
| 73 | 90 | zLogin = mprintf("%t@", g.urlUser); |
| 74 | 91 | }else{ |
| 75 | - for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} | |
| 76 | 92 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 77 | 93 | zLogin = mprintf(""); |
| 78 | 94 | } |
| 79 | - for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } | |
| 95 | + url_tolower(g.urlName); | |
| 80 | 96 | if( c==':' ){ |
| 81 | 97 | g.urlPort = 0; |
| 82 | 98 | i++; |
| 83 | 99 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| 84 | 100 | g.urlPort = g.urlPort*10 + c - '0'; |
| @@ -101,10 +117,46 @@ | ||
| 101 | 117 | g.urlCanonical = mprintf( |
| 102 | 118 | "%s://%s%T:%d%T", |
| 103 | 119 | g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath |
| 104 | 120 | ); |
| 105 | 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 | + 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 | + ); | |
| 106 | 158 | free(zLogin); |
| 107 | 159 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 108 | 160 | g.urlIsFile = 1; |
| 109 | 161 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 110 | 162 | i = 7; |
| @@ -150,19 +202,22 @@ | ||
| 150 | 202 | } |
| 151 | 203 | url_parse(g.argv[2]); |
| 152 | 204 | for(i=0; i<2; i++){ |
| 153 | 205 | printf("g.urlIsFile = %d\n", g.urlIsFile); |
| 154 | 206 | printf("g.urlIsHttps = %d\n", g.urlIsHttps); |
| 207 | + printf("g.urlIsSsh = %d\n", g.urlIsSsh); | |
| 155 | 208 | printf("g.urlProtocol = %s\n", g.urlProtocol); |
| 156 | 209 | printf("g.urlName = %s\n", g.urlName); |
| 210 | + printf("g.urlSshHost = %s\n", g.urlSshHost); | |
| 157 | 211 | printf("g.urlPort = %d\n", g.urlPort); |
| 158 | 212 | printf("g.urlDfltPort = %d\n", g.urlDfltPort); |
| 159 | 213 | printf("g.urlHostname = %s\n", g.urlHostname); |
| 160 | 214 | printf("g.urlPath = %s\n", g.urlPath); |
| 161 | 215 | printf("g.urlUser = %s\n", g.urlUser); |
| 162 | 216 | printf("g.urlPasswd = %s\n", g.urlPasswd); |
| 163 | 217 | printf("g.urlCanonical = %s\n", g.urlCanonical); |
| 218 | + if( g.urlIsFile || g.urlIsSsh ) break; | |
| 164 | 219 | if( i==0 ){ |
| 165 | 220 | printf("********\n"); |
| 166 | 221 | url_enable_proxy("Using proxy: "); |
| 167 | 222 | } |
| 168 | 223 | } |
| 169 | 224 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -17,20 +17,33 @@ | |
| 17 | ** |
| 18 | ** This file contains code for parsing URLs that appear on the command-line |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "url.h" |
| 22 | |
| 23 | /* |
| 24 | ** Parse the given URL. Populate variables in the global "g" structure. |
| 25 | ** |
| 26 | ** g.urlIsFile True if FILE: |
| 27 | ** g.urlIsHttps True if HTTPS: |
| 28 | ** g.urlProtocol "http" or "https" or "file" |
| 29 | ** g.urlName Hostname for HTTP: or HTTPS:. Filename for FILE: |
| 30 | ** g.urlPort TCP port number for HTTP or HTTPS. |
| 31 | ** g.urlDfltPort Default TCP port number (80 or 443). |
| 32 | ** g.urlPath Path name for HTTP or HTTPS. |
| 33 | ** g.urlUser Userid. |
| 34 | ** g.urlPasswd Password. |
| 35 | ** g.urlHostname HOST:PORT or just HOST if port is the default. |
| 36 | ** g.urlCanonical The URL in canonical form, omitting the password |
| @@ -37,10 +50,14 @@ | |
| 37 | ** |
| 38 | ** HTTP url format is: |
| 39 | ** |
| 40 | ** http://userid:password@host:port/path?query#fragment |
| 41 | ** |
| 42 | */ |
| 43 | void url_parse(const char *zUrl){ |
| 44 | int i, j, c; |
| 45 | char *zFile = 0; |
| 46 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| @@ -70,15 +87,14 @@ | |
| 70 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 71 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 72 | i = j; |
| 73 | zLogin = mprintf("%t@", g.urlUser); |
| 74 | }else{ |
| 75 | for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} |
| 76 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 77 | zLogin = mprintf(""); |
| 78 | } |
| 79 | for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); } |
| 80 | if( c==':' ){ |
| 81 | g.urlPort = 0; |
| 82 | i++; |
| 83 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| 84 | g.urlPort = g.urlPort*10 + c - '0'; |
| @@ -101,10 +117,46 @@ | |
| 101 | g.urlCanonical = mprintf( |
| 102 | "%s://%s%T:%d%T", |
| 103 | g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath |
| 104 | ); |
| 105 | } |
| 106 | free(zLogin); |
| 107 | }else if( strncmp(zUrl, "file:", 5)==0 ){ |
| 108 | g.urlIsFile = 1; |
| 109 | if( zUrl[5]=='/' && zUrl[6]=='/' ){ |
| 110 | i = 7; |
| @@ -150,19 +202,22 @@ | |
| 150 | } |
| 151 | url_parse(g.argv[2]); |
| 152 | for(i=0; i<2; i++){ |
| 153 | printf("g.urlIsFile = %d\n", g.urlIsFile); |
| 154 | printf("g.urlIsHttps = %d\n", g.urlIsHttps); |
| 155 | printf("g.urlProtocol = %s\n", g.urlProtocol); |
| 156 | printf("g.urlName = %s\n", g.urlName); |
| 157 | printf("g.urlPort = %d\n", g.urlPort); |
| 158 | printf("g.urlDfltPort = %d\n", g.urlDfltPort); |
| 159 | printf("g.urlHostname = %s\n", g.urlHostname); |
| 160 | printf("g.urlPath = %s\n", g.urlPath); |
| 161 | printf("g.urlUser = %s\n", g.urlUser); |
| 162 | printf("g.urlPasswd = %s\n", g.urlPasswd); |
| 163 | printf("g.urlCanonical = %s\n", g.urlCanonical); |
| 164 | if( i==0 ){ |
| 165 | printf("********\n"); |
| 166 | url_enable_proxy("Using proxy: "); |
| 167 | } |
| 168 | } |
| 169 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -17,20 +17,33 @@ | |
| 17 | ** |
| 18 | ** This file contains code for parsing URLs that appear on the command-line |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "url.h" |
| 22 | |
| 23 | /* |
| 24 | ** Convert a string to lower-case. |
| 25 | */ |
| 26 | static void url_tolower(char *z){ |
| 27 | while( *z ){ |
| 28 | *z = tolower(*z); |
| 29 | z++; |
| 30 | } |
| 31 | } |
| 32 | |
| 33 | /* |
| 34 | ** Parse the given URL. Populate variables in the global "g" structure. |
| 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 |
| @@ -37,10 +50,14 @@ | |
| 50 | ** |
| 51 | ** HTTP url format is: |
| 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; |
| 63 | if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){ |
| @@ -70,15 +87,14 @@ | |
| 87 | for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} |
| 88 | g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); |
| 89 | i = j; |
| 90 | zLogin = mprintf("%t@", g.urlUser); |
| 91 | }else{ |
| 92 | g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); |
| 93 | zLogin = mprintf(""); |
| 94 | } |
| 95 | url_tolower(g.urlName); |
| 96 | if( c==':' ){ |
| 97 | g.urlPort = 0; |
| 98 | i++; |
| 99 | while( (c = zUrl[i])!=0 && isdigit(c) ){ |
| 100 | g.urlPort = g.urlPort*10 + c - '0'; |
| @@ -101,10 +117,46 @@ | |
| 117 | g.urlCanonical = mprintf( |
| 118 | "%s://%s%T:%d%T", |
| 119 | g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath |
| 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 | 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; |
| @@ -150,19 +202,22 @@ | |
| 202 | } |
| 203 | url_parse(g.argv[2]); |
| 204 | for(i=0; i<2; i++){ |
| 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 | } |
| 224 |
+7
-2
| --- src/winhttp.c | ||
| +++ src/winhttp.c | ||
| @@ -133,11 +133,12 @@ | ||
| 133 | 133 | */ |
| 134 | 134 | void win32_http_server( |
| 135 | 135 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 136 | 136 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 137 | 137 | const char *zStopper, /* Stop server when this file is exists (Or NULL) */ |
| 138 | - const char *zNotFound /* The --notfound option, or NULL */ | |
| 138 | + const char *zNotFound, /* The --notfound option, or NULL */ | |
| 139 | + int flags /* One or more HTTP_SERVER_ flags */ | |
| 139 | 140 | ){ |
| 140 | 141 | WSADATA wd; |
| 141 | 142 | SOCKET s = INVALID_SOCKET; |
| 142 | 143 | SOCKADDR_IN addr; |
| 143 | 144 | int idCnt = 0; |
| @@ -158,11 +159,15 @@ | ||
| 158 | 159 | if( s==INVALID_SOCKET ){ |
| 159 | 160 | fossil_fatal("unable to create a socket"); |
| 160 | 161 | } |
| 161 | 162 | addr.sin_family = AF_INET; |
| 162 | 163 | addr.sin_port = htons(iPort); |
| 163 | - addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 164 | + if( flags & HTTP_SERVER_LOCALHOST ){ | |
| 165 | + addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
| 166 | + }else{ | |
| 167 | + addr.sin_addr.s_addr = htonl(INADDR_ANY); | |
| 168 | + } | |
| 164 | 169 | if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){ |
| 165 | 170 | closesocket(s); |
| 166 | 171 | iPort++; |
| 167 | 172 | continue; |
| 168 | 173 | } |
| 169 | 174 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -133,11 +133,12 @@ | |
| 133 | */ |
| 134 | void win32_http_server( |
| 135 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 136 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 137 | const char *zStopper, /* Stop server when this file is exists (Or NULL) */ |
| 138 | const char *zNotFound /* The --notfound option, or NULL */ |
| 139 | ){ |
| 140 | WSADATA wd; |
| 141 | SOCKET s = INVALID_SOCKET; |
| 142 | SOCKADDR_IN addr; |
| 143 | int idCnt = 0; |
| @@ -158,11 +159,15 @@ | |
| 158 | if( s==INVALID_SOCKET ){ |
| 159 | fossil_fatal("unable to create a socket"); |
| 160 | } |
| 161 | addr.sin_family = AF_INET; |
| 162 | addr.sin_port = htons(iPort); |
| 163 | addr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 164 | if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){ |
| 165 | closesocket(s); |
| 166 | iPort++; |
| 167 | continue; |
| 168 | } |
| 169 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -133,11 +133,12 @@ | |
| 133 | */ |
| 134 | void win32_http_server( |
| 135 | int mnPort, int mxPort, /* Range of allowed TCP port numbers */ |
| 136 | const char *zBrowser, /* Command to launch browser. (Or NULL) */ |
| 137 | const char *zStopper, /* Stop server when this file is exists (Or NULL) */ |
| 138 | const char *zNotFound, /* The --notfound option, or NULL */ |
| 139 | int flags /* One or more HTTP_SERVER_ flags */ |
| 140 | ){ |
| 141 | WSADATA wd; |
| 142 | SOCKET s = INVALID_SOCKET; |
| 143 | SOCKADDR_IN addr; |
| 144 | int idCnt = 0; |
| @@ -158,11 +159,15 @@ | |
| 159 | if( s==INVALID_SOCKET ){ |
| 160 | fossil_fatal("unable to create a socket"); |
| 161 | } |
| 162 | addr.sin_family = AF_INET; |
| 163 | addr.sin_port = htons(iPort); |
| 164 | if( flags & HTTP_SERVER_LOCALHOST ){ |
| 165 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 166 | }else{ |
| 167 | addr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 168 | } |
| 169 | if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){ |
| 170 | closesocket(s); |
| 171 | iPort++; |
| 172 | continue; |
| 173 | } |
| 174 |
+1
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -986,10 +986,11 @@ | ||
| 986 | 986 | if( pushFlag ){ |
| 987 | 987 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 988 | 988 | nCardSent++; |
| 989 | 989 | } |
| 990 | 990 | manifest_crosslink_begin(); |
| 991 | + transport_global_startup(); | |
| 991 | 992 | fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas"); |
| 992 | 993 | |
| 993 | 994 | while( go ){ |
| 994 | 995 | int newPhantom = 0; |
| 995 | 996 | char *zRandomness; |
| 996 | 997 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -986,10 +986,11 @@ | |
| 986 | if( pushFlag ){ |
| 987 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 988 | nCardSent++; |
| 989 | } |
| 990 | manifest_crosslink_begin(); |
| 991 | fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas"); |
| 992 | |
| 993 | while( go ){ |
| 994 | int newPhantom = 0; |
| 995 | char *zRandomness; |
| 996 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -986,10 +986,11 @@ | |
| 986 | if( pushFlag ){ |
| 987 | blob_appendf(&send, "push %s %s\n", zSCode, zPCode); |
| 988 | nCardSent++; |
| 989 | } |
| 990 | manifest_crosslink_begin(); |
| 991 | transport_global_startup(); |
| 992 | fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas"); |
| 993 | |
| 994 | while( go ){ |
| 995 | int newPhantom = 0; |
| 996 | char *zRandomness; |
| 997 |