Fossil SCM

Merge the ssh:// sync enhancement into the trunk.

drh 2010-08-25 20:00 trunk merge
Commit 0e42cc1b77f07d00546d001f3052201cd3258e19
+65 -12
--- src/cgi.c
+++ src/cgi.c
@@ -1017,10 +1017,22 @@
10171017
"<html><body>Unrecognized HTTP Request</body></html>\n"
10181018
);
10191019
cgi_reply();
10201020
fossil_exit(0);
10211021
}
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
+}
10221034
10231035
/*
10241036
** Panic and die while processing a webpage.
10251037
*/
10261038
void cgi_panic(const char *zFormat, ...){
@@ -1073,10 +1085,11 @@
10731085
void cgi_handle_http_request(const char *zIpAddr){
10741086
char *z, *zToken;
10751087
int i;
10761088
struct sockaddr_in remoteName;
10771089
size_t size = sizeof(struct sockaddr_in);
1090
+ int accessTokenSeen = 0;
10781091
char zLine[2000]; /* A single line of input. */
10791092
10801093
g.fullHttpReply = 1;
10811094
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
10821095
malformed_request();
@@ -1122,34 +1135,56 @@
11221135
while( isspace(*zVal) ){ zVal++; }
11231136
i = strlen(zVal);
11241137
while( i>0 && isspace(zVal[i-1]) ){ i--; }
11251138
zVal[i] = 0;
11261139
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 ){
11301141
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);
11351142
}else if( strcmp(zFieldName,"content-type:")==0 ){
11361143
cgi_setenv("CONTENT_TYPE", zVal);
11371144
}else if( strcmp(zFieldName,"cookie:")==0 ){
11381145
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);
11391150
}else if( strcmp(zFieldName,"if-none-match:")==0 ){
11401151
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
11411152
}else if( strcmp(zFieldName,"if-modified-since:")==0 ){
11421153
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);
11451166
}
1167
+#endif
1168
+ }
1169
+
1170
+ if( g.zAccessToken && !accessTokenSeen ){
1171
+ forbidden_request();
11461172
}
11471173
11481174
cgi_init();
11491175
}
11501176
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
+
11511186
/*
11521187
** Maximum number of child processes that we can have running
11531188
** at one time before we start slowing things down.
11541189
*/
11551190
#define MAX_PARALLEL 2
@@ -1162,11 +1197,11 @@
11621197
** The parent never returns from this procedure.
11631198
**
11641199
** Return 0 to each child as it runs. If unable to establish a
11651200
** listening socket, return non-zero.
11661201
*/
1167
-int cgi_http_server(int mnPort, int mxPort, char *zBrowser){
1202
+int cgi_http_server(int mnPort, int mxPort, char *zBrowser, int flags){
11681203
#ifdef __MINGW32__
11691204
/* Use win32_http_server() instead */
11701205
fossil_exit(1);
11711206
#else
11721207
int listener = -1; /* The server socket */
@@ -1181,11 +1216,15 @@
11811216
int iPort = mnPort;
11821217
11831218
while( iPort<=mxPort ){
11841219
memset(&inaddr, 0, sizeof(inaddr));
11851220
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
+ }
11871226
inaddr.sin_port = htons(iPort);
11881227
listener = socket(AF_INET, SOCK_STREAM, 0);
11891228
if( listener<0 ){
11901229
iPort++;
11911230
continue;
@@ -1226,11 +1265,25 @@
12261265
}
12271266
delay.tv_sec = 60;
12281267
delay.tv_usec = 0;
12291268
FD_ZERO(&readfds);
12301269
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) ){
12321285
lenaddr = sizeof(inaddr);
12331286
connection = accept(listener, (struct sockaddr*)&inaddr,
12341287
(socklen_t*) &lenaddr);
12351288
if( connection>=0 ){
12361289
child = fork();
12371290
--- 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
--- src/config.h
+++ src/config.h
@@ -29,10 +29,12 @@
2929
#include <stdarg.h>
3030
#include <assert.h>
3131
#ifdef __MINGW32__
3232
# include <windows.h>
3333
#else
34
+# include <sys/types.h>
35
+# include <signal.h>
3436
# include <pwd.h>
3537
#endif
3638
3739
#include "sqlite3.h"
3840
3941
--- 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 @@
111111
if( g.fHttpTrace ){
112112
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
113113
}else{
114114
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
115115
}
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");
117121
}
118122
119123
/*
120124
** Sign the content in pSend, compress it, and send it to the server
121125
** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
122126
--- 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
--- src/http_transport.c
+++ src/http_transport.c
@@ -63,10 +63,51 @@
6363
if( resetFlag ){
6464
transport.nSent = 0;
6565
transport.nRcvd = 0;
6666
}
6767
}
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
+}
68109
69110
/*
70111
** Open a connection to the server. The server is defined by the following
71112
** global variables:
72113
**
@@ -313,13 +354,19 @@
313354
/* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
314355
return &transport.pBuf[iStart];
315356
}
316357
317358
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
+ }
318365
if( g.urlIsHttps ){
319366
#ifdef FOSSIL_ENABLE_SSL
320367
ssl_global_shutdown();
321368
#endif
322369
}else{
323370
socket_global_shutdown();
324371
}
325372
}
326373
--- 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 @@
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 */
8892
8993
int urlIsFile; /* True if a "file:" url */
9094
int urlIsHttps; /* True if a "https:" url */
95
+ int urlIsSsh; /* True if an "ssh:" url */
9196
char *urlName; /* Hostname for http: or filename for file: */
97
+ char *urlSshHost; /* Hostname for ssh: tunnels */
9298
char *urlHostname; /* The HOST: parameter on http headers */
9399
char *urlProtocol; /* "http" or "https" */
94100
int urlPort; /* TCP port number for http: or https: */
95101
int urlDfltPort; /* The default port for the given protocol */
102
+ int urlSshPort; /* TCP port for SSH */
96103
char *urlPath; /* Pathname for http: */
97104
char *urlUser; /* User id for http: */
98105
char *urlPasswd; /* Password for http: */
99106
char *urlCanonical; /* Canonical representation of the URL */
100107
char *urlProxyAuth; /* Proxy-Authorizer: string */
@@ -969,10 +976,11 @@
969976
}
970977
#endif
971978
#endif
972979
973980
/*
981
+** COMMAND: sshd
974982
** COMMAND: server
975983
** COMMAND: ui
976984
**
977985
** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
978986
** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
@@ -982,24 +990,29 @@
982990
** --port option. The optional argument is the name of the repository.
983991
** The repository argument may be omitted if the working directory is
984992
** within an open checkout.
985993
**
986994
** 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.
988997
**
989998
** In the "server" command, the REPOSITORY can be a directory (aka folder)
990999
** that contains one or more respositories with names ending in ".fossil".
9911000
** In that case, the first element of the URL is used to select among the
9921001
** various repositories.
1002
+**
1003
+** The "ui" or "server" verb can also be "sshd". This is used internally
1004
+** by the ssh:// sync method.
9931005
*/
9941006
void cmd_webserver(void){
9951007
int iPort, mxPort; /* Range of TCP ports allowed */
9961008
const char *zPort; /* Value of the --port option */
9971009
char *zBrowser; /* Name of web browser program */
9981010
char *zBrowserCmd = 0; /* Command to launch the web browser */
9991011
int isUiCmd; /* True if command is "ui", not "server' */
10001012
const char *zNotFound; /* The --notfound option or NULL */
1013
+ int flags = 0; /* Server flags */
10011014
10021015
#ifdef __MINGW32__
10031016
const char *zStopperFile; /* Name of file used to terminate server */
10041017
zStopperFile = find_option("stopper", 0, 1);
10051018
#endif
@@ -1010,17 +1023,30 @@
10101023
}
10111024
zPort = find_option("port", "P", 1);
10121025
zNotFound = find_option("notfound", 0, 1);
10131026
if( g.argc!=2 && g.argc!=3 ) usage("?REPOSITORY?");
10141027
isUiCmd = g.argv[1][0]=='u';
1028
+ if( isUiCmd ) flags |= HTTP_SERVER_LOCALHOST;
10151029
find_server_repository(isUiCmd);
10161030
if( zPort ){
10171031
iPort = mxPort = atoi(zPort);
10181032
}else{
10191033
iPort = db_get_int("http-port", 8080);
10201034
mxPort = iPort+100;
10211035
}
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
+ }
10221048
#ifndef __MINGW32__
10231049
/* Unix implementation */
10241050
if( isUiCmd ){
10251051
#if !defined(__DARWIN__) && !defined(__APPLE__)
10261052
zBrowser = db_get("web-browser", 0);
@@ -1039,11 +1065,11 @@
10391065
zBrowser = db_get("web-browser", "open");
10401066
#endif
10411067
zBrowserCmd = mprintf("%s http://localhost:%%d/ &", zBrowser);
10421068
}
10431069
db_close();
1044
- if( cgi_http_server(iPort, mxPort, zBrowserCmd) ){
1070
+ if( cgi_http_server(iPort, mxPort, zBrowserCmd, flags) ){
10451071
fossil_fatal("unable to listen on TCP socket %d", iPort);
10461072
}
10471073
g.httpIn = stdin;
10481074
g.httpOut = stdout;
10491075
if( g.fHttpTrace || g.fSqlTrace ){
@@ -1059,8 +1085,8 @@
10591085
if( isUiCmd ){
10601086
zBrowser = db_get("web-browser", "start");
10611087
zBrowserCmd = mprintf("%s http://127.0.0.1:%%d/", zBrowser);
10621088
}
10631089
db_close();
1064
- win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound);
1090
+ win32_http_server(iPort, mxPort, zBrowserCmd, zStopperFile, zNotFound, flags);
10651091
#endif
10661092
}
10671093
--- 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 @@
5151
$(SRCDIR)/md5.c \
5252
$(SRCDIR)/merge.c \
5353
$(SRCDIR)/merge3.c \
5454
$(SRCDIR)/name.c \
5555
$(SRCDIR)/pivot.c \
56
+ $(SRCDIR)/popen.c \
5657
$(SRCDIR)/pqueue.c \
5758
$(SRCDIR)/printf.c \
5859
$(SRCDIR)/rebuild.c \
5960
$(SRCDIR)/report.c \
6061
$(SRCDIR)/rss.c \
@@ -123,10 +124,11 @@
123124
md5_.c \
124125
merge_.c \
125126
merge3_.c \
126127
name_.c \
127128
pivot_.c \
129
+ popen_.c \
128130
pqueue_.c \
129131
printf_.c \
130132
rebuild_.c \
131133
report_.c \
132134
rss_.c \
@@ -195,10 +197,11 @@
195197
$(OBJDIR)/md5.o \
196198
$(OBJDIR)/merge.o \
197199
$(OBJDIR)/merge3.o \
198200
$(OBJDIR)/name.o \
199201
$(OBJDIR)/pivot.o \
202
+ $(OBJDIR)/popen.o \
200203
$(OBJDIR)/pqueue.o \
201204
$(OBJDIR)/printf.o \
202205
$(OBJDIR)/rebuild.o \
203206
$(OBJDIR)/report.o \
204207
$(OBJDIR)/rss.o \
@@ -270,16 +273,16 @@
270273
# noop
271274
272275
clean:
273276
rm -f $(OBJDIR)/*.o *_.c $(APPNAME) VERSION.h
274277
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
276279
277280
page_index.h: $(TRANS_SRC) mkindex
278281
./mkindex $(TRANS_SRC) >$@
279282
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
281284
touch headers
282285
headers: Makefile
283286
Makefile:
284287
add_.c: $(SRCDIR)/add.c translate
285288
./translate $(SRCDIR)/add.c >add_.c
@@ -559,10 +562,17 @@
559562
560563
$(OBJDIR)/pivot.o: pivot_.c pivot.h $(SRCDIR)/config.h
561564
$(XTCC) -o $(OBJDIR)/pivot.o -c pivot_.c
562565
563566
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
564574
pqueue_.c: $(SRCDIR)/pqueue.c translate
565575
./translate $(SRCDIR)/pqueue.c >pqueue_.c
566576
567577
$(OBJDIR)/pqueue.o: pqueue_.c pqueue.h $(SRCDIR)/config.h
568578
$(XTCC) -o $(OBJDIR)/pqueue.o -c pqueue_.c
569579
--- 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
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -44,10 +44,11 @@
4444
md5
4545
merge
4646
merge3
4747
name
4848
pivot
49
+ popen
4950
pqueue
5051
printf
5152
rebuild
5253
report
5354
rss
5455
5556
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
--- 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 @@
1717
**
1818
** This file contains code for parsing URLs that appear on the command-line
1919
*/
2020
#include "config.h"
2121
#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
+}
2232
2333
/*
2434
** Parse the given URL. Populate variables in the global "g" structure.
2535
**
2636
** g.urlIsFile True if FILE:
2737
** g.urlIsHttps True if HTTPS:
38
+** g.urlIsSsh True if SSH:
2839
** g.urlProtocol "http" or "https" or "file"
2940
** g.urlName Hostname for HTTP: or HTTPS:. Filename for FILE:
41
+** g.urlSshHost Hostname for SSH: tunnel
3042
** g.urlPort TCP port number for HTTP or HTTPS.
3143
** g.urlDfltPort Default TCP port number (80 or 443).
44
+** g.urlSshPort TCP port for SSH: tunnel
3245
** g.urlPath Path name for HTTP or HTTPS.
3346
** g.urlUser Userid.
3447
** g.urlPasswd Password.
3548
** g.urlHostname HOST:PORT or just HOST if port is the default.
3649
** g.urlCanonical The URL in canonical form, omitting the password
@@ -37,10 +50,14 @@
3750
**
3851
** HTTP url format is:
3952
**
4053
** http://userid:password@host:port/path?query#fragment
4154
**
55
+** SSH url format is:
56
+**
57
+** ssh://userid@host:port/fullpath
58
+**
4259
*/
4360
void url_parse(const char *zUrl){
4461
int i, j, c;
4562
char *zFile = 0;
4663
if( strncmp(zUrl, "http://", 7)==0 || strncmp(zUrl, "https://", 8)==0 ){
@@ -70,15 +87,14 @@
7087
for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
7188
g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
7289
i = j;
7390
zLogin = mprintf("%t@", g.urlUser);
7491
}else{
75
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
7692
g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
7793
zLogin = mprintf("");
7894
}
79
- for(j=0; g.urlName[j]; j++){ g.urlName[j] = tolower(g.urlName[j]); }
95
+ url_tolower(g.urlName);
8096
if( c==':' ){
8197
g.urlPort = 0;
8298
i++;
8399
while( (c = zUrl[i])!=0 && isdigit(c) ){
84100
g.urlPort = g.urlPort*10 + c - '0';
@@ -101,10 +117,46 @@
101117
g.urlCanonical = mprintf(
102118
"%s://%s%T:%d%T",
103119
g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
104120
);
105121
}
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
+ );
106158
free(zLogin);
107159
}else if( strncmp(zUrl, "file:", 5)==0 ){
108160
g.urlIsFile = 1;
109161
if( zUrl[5]=='/' && zUrl[6]=='/' ){
110162
i = 7;
@@ -150,19 +202,22 @@
150202
}
151203
url_parse(g.argv[2]);
152204
for(i=0; i<2; i++){
153205
printf("g.urlIsFile = %d\n", g.urlIsFile);
154206
printf("g.urlIsHttps = %d\n", g.urlIsHttps);
207
+ printf("g.urlIsSsh = %d\n", g.urlIsSsh);
155208
printf("g.urlProtocol = %s\n", g.urlProtocol);
156209
printf("g.urlName = %s\n", g.urlName);
210
+ printf("g.urlSshHost = %s\n", g.urlSshHost);
157211
printf("g.urlPort = %d\n", g.urlPort);
158212
printf("g.urlDfltPort = %d\n", g.urlDfltPort);
159213
printf("g.urlHostname = %s\n", g.urlHostname);
160214
printf("g.urlPath = %s\n", g.urlPath);
161215
printf("g.urlUser = %s\n", g.urlUser);
162216
printf("g.urlPasswd = %s\n", g.urlPasswd);
163217
printf("g.urlCanonical = %s\n", g.urlCanonical);
218
+ if( g.urlIsFile || g.urlIsSsh ) break;
164219
if( i==0 ){
165220
printf("********\n");
166221
url_enable_proxy("Using proxy: ");
167222
}
168223
}
169224
--- 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 @@
133133
*/
134134
void win32_http_server(
135135
int mnPort, int mxPort, /* Range of allowed TCP port numbers */
136136
const char *zBrowser, /* Command to launch browser. (Or NULL) */
137137
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 */
139140
){
140141
WSADATA wd;
141142
SOCKET s = INVALID_SOCKET;
142143
SOCKADDR_IN addr;
143144
int idCnt = 0;
@@ -158,11 +159,15 @@
158159
if( s==INVALID_SOCKET ){
159160
fossil_fatal("unable to create a socket");
160161
}
161162
addr.sin_family = AF_INET;
162163
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
+ }
164169
if( bind(s, (struct sockaddr*)&addr, sizeof(addr))==SOCKET_ERROR ){
165170
closesocket(s);
166171
iPort++;
167172
continue;
168173
}
169174
--- 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 @@
986986
if( pushFlag ){
987987
blob_appendf(&send, "push %s %s\n", zSCode, zPCode);
988988
nCardSent++;
989989
}
990990
manifest_crosslink_begin();
991
+ transport_global_startup();
991992
fossil_print(zLabelFormat, "", "Bytes", "Cards", "Artifacts", "Deltas");
992993
993994
while( go ){
994995
int newPhantom = 0;
995996
char *zRandomness;
996997
--- 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

Keyboard Shortcuts

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