Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | A rework of the SSH sync method that does not use TCP port forwarding. It works in some cases but not other. The failure is probably do to I/O buffering issues. Need further work. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | experimental |
| Files: | files | file ages | folders |
| SHA1: |
192ceef3ca6a572ca251d6379def73fd |
| User & Date: | drh 2010-08-26 02:32:04.000 |
Context
|
2010-08-26
| ||
| 11:27 | Fix buffering issues with ssh://. The ssh:// sync method now works with older, unmodified servers. Added the "?fossil=exe" option to URL processing. ... (check-in: af97726337 user: drh tags: experimental) | |
| 02:32 | A rework of the SSH sync method that does not use TCP port forwarding. It works in some cases but not other. The failure is probably do to I/O buffering issues. Need further work. ... (check-in: 192ceef3ca user: drh tags: experimental) | |
|
2010-08-25
| ||
| 19:55 | Change the "ui" and "sshd" commands so that they bind to INADDR_LOOPBACK rather than INADDR_ANY. Disable the "quit" monitoring on "ui" and "server". Add better error messages explaining that ssh:// is not yet supported on windows. ... (check-in: 2f8e4c4b38 user: drh tags: experimental) | |
Changes
Changes to src/cgi.c.
| ︙ | ︙ | |||
1016 1017 1018 1019 1020 1021 1022 |
cgi_printf(
"<html><body>Unrecognized HTTP Request</body></html>\n"
);
cgi_reply();
fossil_exit(0);
}
| < < < < < < < < < < < < | 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 |
cgi_printf(
"<html><body>Unrecognized HTTP Request</body></html>\n"
);
cgi_reply();
fossil_exit(0);
}
/*
** Panic and die while processing a webpage.
*/
void cgi_panic(const char *zFormat, ...){
va_list ap;
cgi_reset_content();
cgi_set_status(500, "Internal Server Error");
|
| ︙ | ︙ | |||
1083 1084 1085 1086 1087 1088 1089 |
** and subsequent code handles the actual generation of the webpage.
*/
void cgi_handle_http_request(const char *zIpAddr){
char *z, *zToken;
int i;
struct sockaddr_in remoteName;
size_t size = sizeof(struct sockaddr_in);
| < | 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 |
** and subsequent code handles the actual generation of the webpage.
*/
void cgi_handle_http_request(const char *zIpAddr){
char *z, *zToken;
int i;
struct sockaddr_in remoteName;
size_t size = sizeof(struct sockaddr_in);
char zLine[2000]; /* A single line of input. */
g.fullHttpReply = 1;
if( fgets(zLine, sizeof(zLine),g.httpIn)==0 ){
malformed_request();
}
zToken = extract_token(zLine, &z);
|
| ︙ | ︙ | |||
1147 1148 1149 1150 1151 1152 1153 |
cgi_setenv("HTTPS", zVal);
}else if( strcmp(zFieldName,"host:")==0 ){
cgi_setenv("HTTP_HOST", zVal);
}else if( strcmp(zFieldName,"if-none-match:")==0 ){
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
}else if( strcmp(zFieldName,"if-modified-since:")==0 ){
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
| < < < < < < < < < < < | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 |
cgi_setenv("HTTPS", zVal);
}else if( strcmp(zFieldName,"host:")==0 ){
cgi_setenv("HTTP_HOST", zVal);
}else if( strcmp(zFieldName,"if-none-match:")==0 ){
cgi_setenv("HTTP_IF_NONE_MATCH", zVal);
}else if( strcmp(zFieldName,"if-modified-since:")==0 ){
cgi_setenv("HTTP_IF_MODIFIED_SINCE", zVal);
}
#if 0
else if( strcmp(zFieldName,"referer:")==0 ){
cgi_setenv("HTTP_REFERER", zVal);
}else if( strcmp(zFieldName,"user-agent:")==0 ){
cgi_setenv("HTTP_USER_AGENT", zVal);
}
#endif
}
cgi_init();
}
#if INTERFACE
/*
** Bitmap values for the flags parameter to cgi_http_server().
*/
#define HTTP_SERVER_LOCALHOST 0x0001 /* Bind to 127.0.0.1 only */
#endif /* INTERFACE */
/*
** Maximum number of child processes that we can have running
** at one time before we start slowing things down.
*/
|
| ︙ | ︙ | |||
1263 1264 1265 1266 1267 1268 1269 |
/* Slow down if connections are arriving too fast */
sleep( nchildren-MAX_PARALLEL );
}
delay.tv_sec = 60;
delay.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET( listener, &readfds);
| < < < < < < < < < < < < < | 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 |
/* Slow down if connections are arriving too fast */
sleep( nchildren-MAX_PARALLEL );
}
delay.tv_sec = 60;
delay.tv_usec = 0;
FD_ZERO(&readfds);
FD_SET( listener, &readfds);
select( listener+1, &readfds, 0, 0, &delay);
if( FD_ISSET(listener, &readfds) ){
lenaddr = sizeof(inaddr);
connection = accept(listener, (struct sockaddr*)&inaddr,
(socklen_t*) &lenaddr);
if( connection>=0 ){
child = fork();
if( child!=0 ){
|
| ︙ | ︙ |
Changes to src/http.c.
| ︙ | ︙ | |||
109 110 111 112 113 114 115 |
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n");
if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
}
| | < < < < | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname);
blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n");
if( g.fHttpTrace ){
blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(pHdr, "Content-Type: application/x-fossil\r\n");
}
blob_appendf(pHdr, "Content-Length: %d\r\n\r\n", blob_size(pPayload));
}
/*
** Sign the content in pSend, compress it, and send it to the server
** via HTTP or HTTPS. Get a reply, uncompress the reply, and store the reply
** in pRecv. pRecv is assumed to be uninitialized when
** this routine is called - this routine will initialize it.
|
| ︙ | ︙ |
Changes to src/http_transport.c.
| ︙ | ︙ | |||
68 69 70 71 72 73 74 |
/*
** Global initialization of the transport layer
*/
void transport_global_startup(void){
if( g.urlIsSsh ){
char *zCmd;
| < | < < < < | < < < > > < < | < | < | > > > | 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
/*
** Global initialization of the transport layer
*/
void transport_global_startup(void){
if( g.urlIsSsh ){
char *zCmd;
char zIn[200];
#ifdef __MINGW32__
fossil_fatal("the ssh:// sync method is currently only supported on unix");
#endif
if( g.urlUser && g.urlUser[0] ){
zCmd = mprintf("ssh -e none %s@%s", g.urlUser, g.urlName);
}else{
zCmd = mprintf("ssh -e none %s", g.urlName);
}
printf("%s\n", zCmd);
popen2(zCmd, &g.sshIn, &g.sshOut, &g.sshPid);
if( g.sshPid==0 ){
fossil_fatal("cannot start ssh tunnel using [%s]", zCmd);
}
free(zCmd);
fprintf(g.sshOut, "echo test\n");
fflush(g.sshOut);
zIn[0] = 0;
fgets(zIn, sizeof(zIn), g.sshIn);
if( memcmp(zIn, "test", 4)!=0 ){
fossil_fatal("ssh connection failed");
}
}
}
/*
** Open a connection to the server. The server is defined by the following
** global variables:
**
** g.urlName Name of the server. Ex: www.fossil-scm.org
** g.urlPort TCP/IP port. Ex: 80
** g.urlIsHttps Use TLS for the connection
**
** Return the number of errors.
*/
int transport_open(void){
int rc = 0;
if( transport.isOpen==0 ){
if( g.urlIsSsh ){
fprintf(g.sshOut, "fossil test-http \"%s\"\n", g.urlPath);
fflush(g.sshOut);
}else if( g.urlIsHttps ){
#ifdef FOSSIL_ENABLE_SSL
rc = ssl_open();
if( rc==0 ) transport.isOpen = 1;
#else
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
rc = 1;
#endif
|
| ︙ | ︙ | |||
154 155 156 157 158 159 160 |
void transport_close(void){
if( transport.isOpen ){
free(transport.pBuf);
transport.pBuf = 0;
transport.nAlloc = 0;
transport.nUsed = 0;
transport.iCursor = 0;
| | > > | 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
void transport_close(void){
if( transport.isOpen ){
free(transport.pBuf);
transport.pBuf = 0;
transport.nAlloc = 0;
transport.nUsed = 0;
transport.iCursor = 0;
if( g.urlIsSsh ){
/* No-op */
}else if( g.urlIsHttps ){
#ifdef FOSSIL_ENABLE_SSL
ssl_close();
#endif
}else if( g.urlIsFile ){
if( transport.pFile ){
fclose(transport.pFile);
transport.pFile = 0;
|
| ︙ | ︙ | |||
181 182 183 184 185 186 187 |
/*
** Send content over the wire.
*/
void transport_send(Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
| | > > > | 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
/*
** Send content over the wire.
*/
void transport_send(Blob *toSend){
char *z = blob_buffer(toSend);
int n = blob_size(toSend);
transport.nSent += n;
if( g.urlIsSsh ){
fwrite(z, 1, n, g.sshOut);
fflush(g.sshOut);
}else if( g.urlIsHttps ){
#ifdef FOSSIL_ENABLE_SSL
int sent;
while( n>0 ){
sent = ssl_send(0, z, n);
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
if( sent<=0 ) break;
n -= sent;
|
| ︙ | ︙ | |||
209 210 211 212 213 214 215 |
}
/*
** This routine is called when the outbound message is complete and
** it is time to being recieving a reply.
*/
void transport_flip(void){
| | > > > | 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
}
/*
** This routine is called when the outbound message is complete and
** it is time to being recieving a reply.
*/
void transport_flip(void){
if( g.urlIsSsh ){
fprintf(g.sshOut, "\n\n");
fflush(g.sshOut);
}else if( g.urlIsFile ){
char *zCmd;
fclose(transport.pFile);
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1",
g.argv[0], g.urlName, transport.zOutFile, transport.zInFile
);
portable_system(zCmd);
free(zCmd);
|
| ︙ | ︙ | |||
256 257 258 259 260 261 262 |
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
int got;
| > > | < < > | 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 |
}
N -= toMove;
zBuf += toMove;
nByte += toMove;
}
if( N>0 ){
int got;
if( g.sshIn ){
got = fread(zBuf, 1, N, g.sshIn);
}else if( g.urlIsHttps ){
#ifdef FOSSIL_ENABLE_SSL
got = ssl_receive(0, zBuf, N);
#else
got = 0;
#endif
}else if( g.urlIsFile ){
got = fread(zBuf, 1, N, transport.pFile);
}else{
got = socket_receive(0, zBuf, N);
}
printf("received %d of %d bytes\n", got, N); fflush(stdout);
if( got>0 ){
nByte += got;
transport.nRcvd += got;
}
}
return nByte;
}
|
| ︙ | ︙ |
Changes to src/main.c.
| ︙ | ︙ | |||
81 82 83 84 85 86 87 | Th_Interp *interp; /* The TH1 interpreter */ FILE *httpIn; /* Accept HTTP input from here */ FILE *httpOut; /* Send HTTP output here */ int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ | < < < | 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | Th_Interp *interp; /* The TH1 interpreter */ FILE *httpIn; /* Accept HTTP input from here */ FILE *httpOut; /* Send HTTP output here */ int xlinkClusterOnly; /* Set when cloning. Only process clusters */ int fTimeFormat; /* 1 for UTC. 2 for localtime. 0 not yet selected */ int *aCommitFile; /* Array of files to be committed */ int markPrivate; /* All new artifacts are private if true */ int sshPid; /* Process id of ssh subprocess */ FILE *sshIn; /* From ssh subprocess to this */ FILE *sshOut; /* From this to ssh subprocess */ int urlIsFile; /* True if a "file:" url */ int urlIsHttps; /* True if a "https:" url */ int urlIsSsh; /* True if an "ssh:" url */ char *urlName; /* Hostname for http: or filename for file: */ char *urlHostname; /* The HOST: parameter on http headers */ char *urlProtocol; /* "http" or "https" */ int urlPort; /* TCP port number for http: or https: */ int urlDfltPort; /* The default port for the given protocol */ char *urlPath; /* Pathname for http: */ char *urlUser; /* User id for http: */ char *urlPasswd; /* Password for http: */ char *urlCanonical; /* Canonical representation of the URL */ char *urlProxyAuth; /* Proxy-Authorizer: string */ int dontKeepUrl; /* Do not persist the URL */ |
| ︙ | ︙ | |||
974 975 976 977 978 979 980 | } return 0; } #endif #endif /* | < < < < | 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 |
}
return 0;
}
#endif
#endif
/*
** COMMAND: server
** COMMAND: ui
**
** Usage: %fossil server ?-P|--port TCPPORT? ?REPOSITORY?
** Or: %fossil ui ?-P|--port TCPPORT? ?REPOSITORY?
**
** Open a socket and begin listening and responding to HTTP requests on
** TCP port 8080, or on any other TCP port defined by the -P or
** --port option. The optional argument is the name of the repository.
** The repository argument may be omitted if the working directory is
** within an open checkout.
**
** The "ui" command automatically starts a web browser after initializing
** the web server. The "ui" command also binds to 127.0.0.1 and so will
** only process HTTP traffic from the local machine.
**
** In the "server" command, the REPOSITORY can be a directory (aka folder)
** that contains one or more respositories with names ending in ".fossil".
** In that case, the first element of the URL is used to select among the
** various repositories.
*/
void cmd_webserver(void){
int iPort, mxPort; /* Range of TCP ports allowed */
const char *zPort; /* Value of the --port option */
char *zBrowser; /* Name of web browser program */
char *zBrowserCmd = 0; /* Command to launch the web browser */
int isUiCmd; /* True if command is "ui", not "server' */
|
| ︙ | ︙ | |||
1029 1030 1031 1032 1033 1034 1035 |
find_server_repository(isUiCmd);
if( zPort ){
iPort = mxPort = atoi(zPort);
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
| < < < < < < < < < < < < | 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 |
find_server_repository(isUiCmd);
if( zPort ){
iPort = mxPort = atoi(zPort);
}else{
iPort = db_get_int("http-port", 8080);
mxPort = iPort+100;
}
#ifndef __MINGW32__
/* Unix implementation */
if( isUiCmd ){
#if !defined(__DARWIN__) && !defined(__APPLE__)
zBrowser = db_get("web-browser", 0);
if( zBrowser==0 ){
static char *azBrowserProg[] = { "xdg-open", "gnome-open", "firefox" };
|
| ︙ | ︙ |
Changes to src/url.c.
| ︙ | ︙ | |||
33 34 35 36 37 38 39 | /* ** Parse the given URL. Populate variables in the global "g" structure. ** ** g.urlIsFile True if FILE: ** g.urlIsHttps True if HTTPS: ** g.urlIsSsh True if SSH: ** g.urlProtocol "http" or "https" or "file" | | < < | 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | /* ** Parse the given URL. Populate variables in the global "g" structure. ** ** g.urlIsFile True if FILE: ** g.urlIsHttps True if HTTPS: ** g.urlIsSsh True if SSH: ** g.urlProtocol "http" or "https" or "file" ** g.urlName Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE: ** g.urlPort TCP port number for HTTP or HTTPS. ** g.urlDfltPort Default TCP port number (80 or 443). ** g.urlPath Path name for HTTP or HTTPS. ** g.urlUser Userid. ** g.urlPasswd Password. ** g.urlHostname HOST:PORT or just HOST if port is the default. ** g.urlCanonical The URL in canonical form, omitting the password ** ** HTTP url format is: |
| ︙ | ︙ | |||
118 119 120 121 122 123 124 |
"%s://%s%T:%d%T",
g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
);
}
free(zLogin);
}else if( strncmp(zUrl, "ssh://", 6)==0 ){
char *zLogin;
| < < | | | < | | | > | | 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
"%s://%s%T:%d%T",
g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath
);
}
free(zLogin);
}else if( strncmp(zUrl, "ssh://", 6)==0 ){
char *zLogin;
g.urlIsFile = 0;
g.urlIsSsh = 1;
g.urlProtocol = "ssh";
g.urlPort = 22;
g.urlDfltPort = 22;
g.urlPasswd = "(not-used)";
for(i=6; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
if( c=='@' ){
for(j=6; j<i && zUrl[j]!=':'; j++){}
g.urlUser = mprintf("%.*s", j-6, &zUrl[6]);
dehttpize(g.urlUser);
if( j<i ){
g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
dehttpize(g.urlPasswd);
}
for(j=i+1; (c=zUrl[j])!=0 && c!='/'; j++){}
g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
i = j;
zLogin = mprintf("%t@", g.urlUser);
}else{
g.urlName = mprintf("%.*s", i-6, &zUrl[6]);
zLogin = mprintf("");
}
url_tolower(g.urlName);
g.urlHostname = g.urlName;
g.urlPath = mprintf(&zUrl[i+1]);
dehttpize(g.urlPath);
g.urlCanonical = mprintf(
"ssh://%s%T/%T",
zLogin, g.urlName, g.urlPath
);
free(zLogin);
}else if( strncmp(zUrl, "file:", 5)==0 ){
g.urlIsFile = 1;
if( zUrl[5]=='/' && zUrl[6]=='/' ){
i = 7;
}else{
|
| ︙ | ︙ | |||
203 204 205 206 207 208 209 |
url_parse(g.argv[2]);
for(i=0; i<2; i++){
printf("g.urlIsFile = %d\n", g.urlIsFile);
printf("g.urlIsHttps = %d\n", g.urlIsHttps);
printf("g.urlIsSsh = %d\n", g.urlIsSsh);
printf("g.urlProtocol = %s\n", g.urlProtocol);
printf("g.urlName = %s\n", g.urlName);
| < | 199 200 201 202 203 204 205 206 207 208 209 210 211 212 |
url_parse(g.argv[2]);
for(i=0; i<2; i++){
printf("g.urlIsFile = %d\n", g.urlIsFile);
printf("g.urlIsHttps = %d\n", g.urlIsHttps);
printf("g.urlIsSsh = %d\n", g.urlIsSsh);
printf("g.urlProtocol = %s\n", g.urlProtocol);
printf("g.urlName = %s\n", g.urlName);
printf("g.urlPort = %d\n", g.urlPort);
printf("g.urlDfltPort = %d\n", g.urlDfltPort);
printf("g.urlHostname = %s\n", g.urlHostname);
printf("g.urlPath = %s\n", g.urlPath);
printf("g.urlUser = %s\n", g.urlUser);
printf("g.urlPasswd = %s\n", g.urlPasswd);
printf("g.urlCanonical = %s\n", g.urlCanonical);
|
| ︙ | ︙ |