Fossil SCM

Phase 3, the TH1 http command now uses non-global URL data. This also required heavy refactoring of some other callers that use the global URL data.

mistachkin 2013-10-14 07:08 UTC tkt-change-hook
Commit 8ce9c1af8f60a6471537b08275406c74f13ce846
+11 -11
--- src/http.c
+++ src/http.c
@@ -144,12 +144,12 @@
144144
char *zLine; /* A single line of the reply header */
145145
int i; /* Loop counter */
146146
int isError = 0; /* True if the reply is an error message */
147147
int isCompressed = 1; /* True if the reply is compressed */
148148
149
- if( transport_open() ){
150
- fossil_warning(transport_errmsg());
149
+ if( transport_open(GLOBAL_URL()) ){
150
+ fossil_warning(transport_errmsg(GLOBAL_URL()));
151151
return 1;
152152
}
153153
154154
/* Construct the login card and prepare the complete payload */
155155
blob_zero(&login);
@@ -191,22 +191,22 @@
191191
}
192192
193193
/*
194194
** Send the request to the server.
195195
*/
196
- transport_send(&hdr);
197
- transport_send(&payload);
196
+ transport_send(GLOBAL_URL(), &hdr);
197
+ transport_send(GLOBAL_URL(), &payload);
198198
blob_reset(&hdr);
199199
blob_reset(&payload);
200
- transport_flip();
200
+ transport_flip(GLOBAL_URL());
201201
202202
/*
203203
** Read and interpret the server reply
204204
*/
205205
closeConnection = 1;
206206
iLength = -1;
207
- while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
207
+ while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
208208
/* printf("[%s]\n", zLine); fflush(stdout); */
209209
if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
210210
if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
211211
if( rc!=200 && rc!=302 ){
212212
int ii;
@@ -255,11 +255,11 @@
255255
j -= 4;
256256
zLine[j] = 0;
257257
}
258258
fossil_print("redirect to %s\n", &zLine[i]);
259259
url_parse(&zLine[i], 0);
260
- transport_close();
260
+ transport_close(GLOBAL_URL());
261261
return http_exchange(pSend, pReply, useLogin, maxRedirect);
262262
}else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
263263
if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
264264
isCompressed = 0;
265265
}else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +282,11 @@
282282
/*
283283
** Extract the reply payload that follows the header
284284
*/
285285
blob_zero(pReply);
286286
blob_resize(pReply, iLength);
287
- iLength = transport_receive(blob_buffer(pReply), iLength);
287
+ iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
288288
blob_resize(pReply, iLength);
289289
if( isError ){
290290
char *z;
291291
int i, j;
292292
z = blob_str(pReply);
@@ -311,18 +311,18 @@
311311
**
312312
** For SSH we will leave the connection open.
313313
*/
314314
if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315315
if( closeConnection ){
316
- transport_close();
316
+ transport_close(GLOBAL_URL());
317317
}else{
318
- transport_rewind();
318
+ transport_rewind(GLOBAL_URL());
319319
}
320320
return 0;
321321
322322
/*
323323
** Jump to here if an error is seen.
324324
*/
325325
write_err:
326
- transport_close();
326
+ transport_close(GLOBAL_URL());
327327
return 1;
328328
}
329329
--- src/http.c
+++ src/http.c
@@ -144,12 +144,12 @@
144 char *zLine; /* A single line of the reply header */
145 int i; /* Loop counter */
146 int isError = 0; /* True if the reply is an error message */
147 int isCompressed = 1; /* True if the reply is compressed */
148
149 if( transport_open() ){
150 fossil_warning(transport_errmsg());
151 return 1;
152 }
153
154 /* Construct the login card and prepare the complete payload */
155 blob_zero(&login);
@@ -191,22 +191,22 @@
191 }
192
193 /*
194 ** Send the request to the server.
195 */
196 transport_send(&hdr);
197 transport_send(&payload);
198 blob_reset(&hdr);
199 blob_reset(&payload);
200 transport_flip();
201
202 /*
203 ** Read and interpret the server reply
204 */
205 closeConnection = 1;
206 iLength = -1;
207 while( (zLine = transport_receive_line())!=0 && zLine[0]!=0 ){
208 /* printf("[%s]\n", zLine); fflush(stdout); */
209 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
210 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
211 if( rc!=200 && rc!=302 ){
212 int ii;
@@ -255,11 +255,11 @@
255 j -= 4;
256 zLine[j] = 0;
257 }
258 fossil_print("redirect to %s\n", &zLine[i]);
259 url_parse(&zLine[i], 0);
260 transport_close();
261 return http_exchange(pSend, pReply, useLogin, maxRedirect);
262 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
263 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
264 isCompressed = 0;
265 }else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +282,11 @@
282 /*
283 ** Extract the reply payload that follows the header
284 */
285 blob_zero(pReply);
286 blob_resize(pReply, iLength);
287 iLength = transport_receive(blob_buffer(pReply), iLength);
288 blob_resize(pReply, iLength);
289 if( isError ){
290 char *z;
291 int i, j;
292 z = blob_str(pReply);
@@ -311,18 +311,18 @@
311 **
312 ** For SSH we will leave the connection open.
313 */
314 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315 if( closeConnection ){
316 transport_close();
317 }else{
318 transport_rewind();
319 }
320 return 0;
321
322 /*
323 ** Jump to here if an error is seen.
324 */
325 write_err:
326 transport_close();
327 return 1;
328 }
329
--- src/http.c
+++ src/http.c
@@ -144,12 +144,12 @@
144 char *zLine; /* A single line of the reply header */
145 int i; /* Loop counter */
146 int isError = 0; /* True if the reply is an error message */
147 int isCompressed = 1; /* True if the reply is compressed */
148
149 if( transport_open(GLOBAL_URL()) ){
150 fossil_warning(transport_errmsg(GLOBAL_URL()));
151 return 1;
152 }
153
154 /* Construct the login card and prepare the complete payload */
155 blob_zero(&login);
@@ -191,22 +191,22 @@
191 }
192
193 /*
194 ** Send the request to the server.
195 */
196 transport_send(GLOBAL_URL(), &hdr);
197 transport_send(GLOBAL_URL(), &payload);
198 blob_reset(&hdr);
199 blob_reset(&payload);
200 transport_flip(GLOBAL_URL());
201
202 /*
203 ** Read and interpret the server reply
204 */
205 closeConnection = 1;
206 iLength = -1;
207 while( (zLine = transport_receive_line(GLOBAL_URL()))!=0 && zLine[0]!=0 ){
208 /* printf("[%s]\n", zLine); fflush(stdout); */
209 if( fossil_strnicmp(zLine, "http/1.", 7)==0 ){
210 if( sscanf(zLine, "HTTP/1.%d %d", &iHttpVersion, &rc)!=2 ) goto write_err;
211 if( rc!=200 && rc!=302 ){
212 int ii;
@@ -255,11 +255,11 @@
255 j -= 4;
256 zLine[j] = 0;
257 }
258 fossil_print("redirect to %s\n", &zLine[i]);
259 url_parse(&zLine[i], 0);
260 transport_close(GLOBAL_URL());
261 return http_exchange(pSend, pReply, useLogin, maxRedirect);
262 }else if( fossil_strnicmp(zLine, "content-type: ", 14)==0 ){
263 if( fossil_strnicmp(&zLine[14], "application/x-fossil-debug", -1)==0 ){
264 isCompressed = 0;
265 }else if( fossil_strnicmp(&zLine[14],
@@ -282,11 +282,11 @@
282 /*
283 ** Extract the reply payload that follows the header
284 */
285 blob_zero(pReply);
286 blob_resize(pReply, iLength);
287 iLength = transport_receive(GLOBAL_URL(), blob_buffer(pReply), iLength);
288 blob_resize(pReply, iLength);
289 if( isError ){
290 char *z;
291 int i, j;
292 z = blob_str(pReply);
@@ -311,18 +311,18 @@
311 **
312 ** For SSH we will leave the connection open.
313 */
314 if( ! g.urlIsSsh ) closeConnection = 1; /* FIX ME */
315 if( closeConnection ){
316 transport_close(GLOBAL_URL());
317 }else{
318 transport_rewind(GLOBAL_URL());
319 }
320 return 0;
321
322 /*
323 ** Jump to here if an error is seen.
324 */
325 write_err:
326 transport_close(GLOBAL_URL());
327 return 1;
328 }
329
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131131
** g.urlName Name of the server. Ex: www.fossil-scm.org
132132
** g.urlPort TCP/IP port to use. Ex: 80
133133
**
134134
** Return the number of errors.
135135
*/
136
-int socket_open(void){
136
+int socket_open(UrlData *pUrlData){
137137
static struct sockaddr_in addr; /* The server address */
138138
static int addrIsInit = 0; /* True once addr is initialized */
139139
140140
socket_global_init();
141141
if( !addrIsInit ){
142142
addr.sin_family = AF_INET;
143
- addr.sin_port = htons(g.urlPort);
144
- *(int*)&addr.sin_addr = inet_addr(g.urlName);
143
+ addr.sin_port = htons(pUrlData->port);
144
+ *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
145145
if( -1 == *(int*)&addr.sin_addr ){
146146
#ifndef FOSSIL_STATIC_LINK
147147
struct hostent *pHost;
148
- pHost = gethostbyname(g.urlName);
148
+ pHost = gethostbyname(pUrlData->name);
149149
if( pHost!=0 ){
150150
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151151
}else
152152
#endif
153153
{
154
- socket_set_errmsg("can't resolve host name: %s", g.urlName);
154
+ socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
155155
return 1;
156156
}
157157
}
158158
addrIsInit = 1;
159159
@@ -167,11 +167,12 @@
167167
if( iSocket<0 ){
168168
socket_set_errmsg("cannot create a socket");
169169
return 1;
170170
}
171171
if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172
- socket_set_errmsg("cannot connect to host %s:%d", g.urlName, g.urlPort);
172
+ socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
173
+ pUrlData->port);
173174
socket_close();
174175
return 1;
175176
}
176177
#if !defined(_WIN32)
177178
signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
215216
/*
216217
** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217218
** populated. For hostnames with more than one IP (or if overridden in
218219
** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219220
*/
220
-void socket_ssh_resolve_addr(void){
221
+void socket_ssh_resolve_addr(UrlData *pUrlData){
221222
struct hostent *pHost; /* Used to make best effort for rcvfrom */
222223
struct sockaddr_in addr;
223224
224225
memset(&addr, 0, sizeof(addr));
225
- pHost = gethostbyname(g.urlName);
226
+ pHost = gethostbyname(pUrlData->name);
226227
if( pHost!=0 ){
227228
memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228229
g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229230
}
230231
}
231232
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131 ** g.urlName Name of the server. Ex: www.fossil-scm.org
132 ** g.urlPort TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(void){
137 static struct sockaddr_in addr; /* The server address */
138 static int addrIsInit = 0; /* True once addr is initialized */
139
140 socket_global_init();
141 if( !addrIsInit ){
142 addr.sin_family = AF_INET;
143 addr.sin_port = htons(g.urlPort);
144 *(int*)&addr.sin_addr = inet_addr(g.urlName);
145 if( -1 == *(int*)&addr.sin_addr ){
146 #ifndef FOSSIL_STATIC_LINK
147 struct hostent *pHost;
148 pHost = gethostbyname(g.urlName);
149 if( pHost!=0 ){
150 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151 }else
152 #endif
153 {
154 socket_set_errmsg("can't resolve host name: %s", g.urlName);
155 return 1;
156 }
157 }
158 addrIsInit = 1;
159
@@ -167,11 +167,12 @@
167 if( iSocket<0 ){
168 socket_set_errmsg("cannot create a socket");
169 return 1;
170 }
171 if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172 socket_set_errmsg("cannot connect to host %s:%d", g.urlName, g.urlPort);
 
173 socket_close();
174 return 1;
175 }
176 #if !defined(_WIN32)
177 signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
215 /*
216 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
217 ** populated. For hostnames with more than one IP (or if overridden in
218 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
219 */
220 void socket_ssh_resolve_addr(void){
221 struct hostent *pHost; /* Used to make best effort for rcvfrom */
222 struct sockaddr_in addr;
223
224 memset(&addr, 0, sizeof(addr));
225 pHost = gethostbyname(g.urlName);
226 if( pHost!=0 ){
227 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
228 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
229 }
230 }
231
--- src/http_socket.c
+++ src/http_socket.c
@@ -131,29 +131,29 @@
131 ** g.urlName Name of the server. Ex: www.fossil-scm.org
132 ** g.urlPort TCP/IP port to use. Ex: 80
133 **
134 ** Return the number of errors.
135 */
136 int socket_open(UrlData *pUrlData){
137 static struct sockaddr_in addr; /* The server address */
138 static int addrIsInit = 0; /* True once addr is initialized */
139
140 socket_global_init();
141 if( !addrIsInit ){
142 addr.sin_family = AF_INET;
143 addr.sin_port = htons(pUrlData->port);
144 *(int*)&addr.sin_addr = inet_addr(pUrlData->name);
145 if( -1 == *(int*)&addr.sin_addr ){
146 #ifndef FOSSIL_STATIC_LINK
147 struct hostent *pHost;
148 pHost = gethostbyname(pUrlData->name);
149 if( pHost!=0 ){
150 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
151 }else
152 #endif
153 {
154 socket_set_errmsg("can't resolve host name: %s", pUrlData->name);
155 return 1;
156 }
157 }
158 addrIsInit = 1;
159
@@ -167,11 +167,12 @@
167 if( iSocket<0 ){
168 socket_set_errmsg("cannot create a socket");
169 return 1;
170 }
171 if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){
172 socket_set_errmsg("cannot connect to host %s:%d", pUrlData->name,
173 pUrlData->port);
174 socket_close();
175 return 1;
176 }
177 #if !defined(_WIN32)
178 signal(SIGPIPE, SIG_IGN);
@@ -215,16 +216,16 @@
216 /*
217 ** Attempt to resolve g.urlName to IP and setup g.zIpAddr so rcvfrom gets
218 ** populated. For hostnames with more than one IP (or if overridden in
219 ** ~/.ssh/config) the rcvfrom may not match the host to which we connect.
220 */
221 void socket_ssh_resolve_addr(UrlData *pUrlData){
222 struct hostent *pHost; /* Used to make best effort for rcvfrom */
223 struct sockaddr_in addr;
224
225 memset(&addr, 0, sizeof(addr));
226 pHost = gethostbyname(pUrlData->name);
227 if( pHost!=0 ){
228 memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length);
229 g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr));
230 }
231 }
232
+17 -15
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183183
** g.urlName Name of the server. Ex: www.fossil-scm.org
184184
** g.urlPort TCP/IP port to use. Ex: 80
185185
**
186186
** Return the number of errors.
187187
*/
188
-int ssl_open(void){
188
+int ssl_open(UrlData *pUrlData){
189189
X509 *cert;
190190
int hasSavedCertificate = 0;
191191
int trusted = 0;
192192
unsigned long e;
193193
@@ -194,11 +194,11 @@
194194
ssl_global_init();
195195
196196
/* Get certificate for current server from global config and
197197
* (if we have it in config) add it to certificate store.
198198
*/
199
- cert = ssl_get_certificate(&trusted);
199
+ cert = ssl_get_certificate(pUrlData, &trusted);
200200
if ( cert!=NULL ){
201201
X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202202
X509_free(cert);
203203
hasSavedCertificate = 1;
204204
}
@@ -205,11 +205,11 @@
205205
206206
iBio = BIO_new_ssl_connect(sslCtx);
207207
BIO_get_ssl(iBio, &ssl);
208208
209209
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210
- if( !SSL_set_tlsext_host_name(ssl, g.urlName) ){
210
+ if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){
211211
fossil_warning("WARNING: failed to set server name indication (SNI), "
212212
"continuing without it.\n");
213213
}
214214
#endif
215215
@@ -218,23 +218,25 @@
218218
ssl_set_errmsg("SSL: cannot open SSL (%s)",
219219
ERR_reason_error_string(ERR_get_error()));
220220
return 1;
221221
}
222222
223
- BIO_set_conn_hostname(iBio, g.urlName);
224
- BIO_set_conn_int_port(iBio, &g.urlPort);
223
+ BIO_set_conn_hostname(iBio, pUrlData->name);
224
+ BIO_set_conn_int_port(iBio, &pUrlData->port);
225225
226226
if( BIO_do_connect(iBio)<=0 ){
227227
ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228
- g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
228
+ pUrlData->name, pUrlData->port,
229
+ ERR_reason_error_string(ERR_get_error()));
229230
ssl_close();
230231
return 1;
231232
}
232233
233234
if( BIO_do_handshake(iBio)<=0 ) {
234235
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
235
- g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
236
+ pUrlData->name, pUrlData->port,
237
+ ERR_reason_error_string(ERR_get_error()));
236238
ssl_close();
237239
return 1;
238240
}
239241
/* Check if certificate is valid */
240242
cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
281283
" certificates list\n\n"
282284
"If you are not expecting this message, answer no and "
283285
"contact your server\nadministrator.\n\n"
284286
"Accept certificate for host %s (a=always/y/N)? ",
285287
X509_verify_cert_error_string(e), desc, warning,
286
- g.urlName);
288
+ pUrlData->name);
287289
BIO_free(mem);
288290
289291
prompt_user(prompt, &ans);
290292
free(prompt);
291293
cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
302304
&ans);
303305
cReply = blob_str(&ans)[0];
304306
trusted = ( cReply=='a' || cReply=='A' );
305307
blob_reset(&ans);
306308
}
307
- ssl_save_certificate(cert, trusted);
309
+ ssl_save_certificate(pUrlData, cert, trusted);
308310
}
309311
}
310312
311313
/* Set the Global.zIpAddr variable to the server we are talking to.
312314
** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
323325
}
324326
325327
/*
326328
** Save certificate to global config.
327329
*/
328
-void ssl_save_certificate(X509 *cert, int trusted){
330
+void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
329331
BIO *mem;
330332
char *zCert, *zHost;
331333
332334
mem = BIO_new(BIO_s_mem());
333335
PEM_write_bio_X509(mem, cert);
334336
BIO_write(mem, "", 1); /* nul-terminate mem buffer */
335337
BIO_get_mem_data(mem, &zCert);
336
- zHost = mprintf("cert:%s", g.urlName);
338
+ zHost = mprintf("cert:%s", pUrlData->name);
337339
db_set(zHost, zCert, 1);
338340
free(zHost);
339
- zHost = mprintf("trusted:%s", g.urlName);
341
+ zHost = mprintf("trusted:%s", pUrlData->name);
340342
db_set_int(zHost, trusted, 1);
341343
free(zHost);
342344
BIO_free(mem);
343345
}
344346
345347
/*
346348
** Get certificate for g.urlName from global config.
347349
** Return NULL if no certificate found.
348350
*/
349
-X509 *ssl_get_certificate(int *pTrusted){
351
+X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
350352
char *zHost, *zCert;
351353
BIO *mem;
352354
X509 *cert;
353355
354
- zHost = mprintf("cert:%s", g.urlName);
356
+ zHost = mprintf("cert:%s", pUrlData->name);
355357
zCert = db_get(zHost, NULL);
356358
free(zHost);
357359
if ( zCert==NULL )
358360
return NULL;
359361
360362
if ( pTrusted!=0 ){
361
- zHost = mprintf("trusted:%s", g.urlName);
363
+ zHost = mprintf("trusted:%s", pUrlData->name);
362364
*pTrusted = db_get_int(zHost, 0);
363365
free(zHost);
364366
}
365367
366368
mem = BIO_new(BIO_s_mem());
367369
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183 ** g.urlName Name of the server. Ex: www.fossil-scm.org
184 ** g.urlPort TCP/IP port to use. Ex: 80
185 **
186 ** Return the number of errors.
187 */
188 int ssl_open(void){
189 X509 *cert;
190 int hasSavedCertificate = 0;
191 int trusted = 0;
192 unsigned long e;
193
@@ -194,11 +194,11 @@
194 ssl_global_init();
195
196 /* Get certificate for current server from global config and
197 * (if we have it in config) add it to certificate store.
198 */
199 cert = ssl_get_certificate(&trusted);
200 if ( cert!=NULL ){
201 X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202 X509_free(cert);
203 hasSavedCertificate = 1;
204 }
@@ -205,11 +205,11 @@
205
206 iBio = BIO_new_ssl_connect(sslCtx);
207 BIO_get_ssl(iBio, &ssl);
208
209 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210 if( !SSL_set_tlsext_host_name(ssl, g.urlName) ){
211 fossil_warning("WARNING: failed to set server name indication (SNI), "
212 "continuing without it.\n");
213 }
214 #endif
215
@@ -218,23 +218,25 @@
218 ssl_set_errmsg("SSL: cannot open SSL (%s)",
219 ERR_reason_error_string(ERR_get_error()));
220 return 1;
221 }
222
223 BIO_set_conn_hostname(iBio, g.urlName);
224 BIO_set_conn_int_port(iBio, &g.urlPort);
225
226 if( BIO_do_connect(iBio)<=0 ){
227 ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228 g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
 
229 ssl_close();
230 return 1;
231 }
232
233 if( BIO_do_handshake(iBio)<=0 ) {
234 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
235 g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
 
236 ssl_close();
237 return 1;
238 }
239 /* Check if certificate is valid */
240 cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
281 " certificates list\n\n"
282 "If you are not expecting this message, answer no and "
283 "contact your server\nadministrator.\n\n"
284 "Accept certificate for host %s (a=always/y/N)? ",
285 X509_verify_cert_error_string(e), desc, warning,
286 g.urlName);
287 BIO_free(mem);
288
289 prompt_user(prompt, &ans);
290 free(prompt);
291 cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
302 &ans);
303 cReply = blob_str(&ans)[0];
304 trusted = ( cReply=='a' || cReply=='A' );
305 blob_reset(&ans);
306 }
307 ssl_save_certificate(cert, trusted);
308 }
309 }
310
311 /* Set the Global.zIpAddr variable to the server we are talking to.
312 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
323 }
324
325 /*
326 ** Save certificate to global config.
327 */
328 void ssl_save_certificate(X509 *cert, int trusted){
329 BIO *mem;
330 char *zCert, *zHost;
331
332 mem = BIO_new(BIO_s_mem());
333 PEM_write_bio_X509(mem, cert);
334 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
335 BIO_get_mem_data(mem, &zCert);
336 zHost = mprintf("cert:%s", g.urlName);
337 db_set(zHost, zCert, 1);
338 free(zHost);
339 zHost = mprintf("trusted:%s", g.urlName);
340 db_set_int(zHost, trusted, 1);
341 free(zHost);
342 BIO_free(mem);
343 }
344
345 /*
346 ** Get certificate for g.urlName from global config.
347 ** Return NULL if no certificate found.
348 */
349 X509 *ssl_get_certificate(int *pTrusted){
350 char *zHost, *zCert;
351 BIO *mem;
352 X509 *cert;
353
354 zHost = mprintf("cert:%s", g.urlName);
355 zCert = db_get(zHost, NULL);
356 free(zHost);
357 if ( zCert==NULL )
358 return NULL;
359
360 if ( pTrusted!=0 ){
361 zHost = mprintf("trusted:%s", g.urlName);
362 *pTrusted = db_get_int(zHost, 0);
363 free(zHost);
364 }
365
366 mem = BIO_new(BIO_s_mem());
367
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -183,11 +183,11 @@
183 ** g.urlName Name of the server. Ex: www.fossil-scm.org
184 ** g.urlPort TCP/IP port to use. Ex: 80
185 **
186 ** Return the number of errors.
187 */
188 int ssl_open(UrlData *pUrlData){
189 X509 *cert;
190 int hasSavedCertificate = 0;
191 int trusted = 0;
192 unsigned long e;
193
@@ -194,11 +194,11 @@
194 ssl_global_init();
195
196 /* Get certificate for current server from global config and
197 * (if we have it in config) add it to certificate store.
198 */
199 cert = ssl_get_certificate(pUrlData, &trusted);
200 if ( cert!=NULL ){
201 X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
202 X509_free(cert);
203 hasSavedCertificate = 1;
204 }
@@ -205,11 +205,11 @@
205
206 iBio = BIO_new_ssl_connect(sslCtx);
207 BIO_get_ssl(iBio, &ssl);
208
209 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
210 if( !SSL_set_tlsext_host_name(ssl, pUrlData->name) ){
211 fossil_warning("WARNING: failed to set server name indication (SNI), "
212 "continuing without it.\n");
213 }
214 #endif
215
@@ -218,23 +218,25 @@
218 ssl_set_errmsg("SSL: cannot open SSL (%s)",
219 ERR_reason_error_string(ERR_get_error()));
220 return 1;
221 }
222
223 BIO_set_conn_hostname(iBio, pUrlData->name);
224 BIO_set_conn_int_port(iBio, &pUrlData->port);
225
226 if( BIO_do_connect(iBio)<=0 ){
227 ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
228 pUrlData->name, pUrlData->port,
229 ERR_reason_error_string(ERR_get_error()));
230 ssl_close();
231 return 1;
232 }
233
234 if( BIO_do_handshake(iBio)<=0 ) {
235 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
236 pUrlData->name, pUrlData->port,
237 ERR_reason_error_string(ERR_get_error()));
238 ssl_close();
239 return 1;
240 }
241 /* Check if certificate is valid */
242 cert = SSL_get_peer_certificate(ssl);
@@ -281,11 +283,11 @@
283 " certificates list\n\n"
284 "If you are not expecting this message, answer no and "
285 "contact your server\nadministrator.\n\n"
286 "Accept certificate for host %s (a=always/y/N)? ",
287 X509_verify_cert_error_string(e), desc, warning,
288 pUrlData->name);
289 BIO_free(mem);
290
291 prompt_user(prompt, &ans);
292 free(prompt);
293 cReply = blob_str(&ans)[0];
@@ -302,11 +304,11 @@
304 &ans);
305 cReply = blob_str(&ans)[0];
306 trusted = ( cReply=='a' || cReply=='A' );
307 blob_reset(&ans);
308 }
309 ssl_save_certificate(pUrlData, cert, trusted);
310 }
311 }
312
313 /* Set the Global.zIpAddr variable to the server we are talking to.
314 ** This is used to populate the ipaddr column of the rcvfrom table,
@@ -323,44 +325,44 @@
325 }
326
327 /*
328 ** Save certificate to global config.
329 */
330 void ssl_save_certificate(UrlData *pUrlData, X509 *cert, int trusted){
331 BIO *mem;
332 char *zCert, *zHost;
333
334 mem = BIO_new(BIO_s_mem());
335 PEM_write_bio_X509(mem, cert);
336 BIO_write(mem, "", 1); /* nul-terminate mem buffer */
337 BIO_get_mem_data(mem, &zCert);
338 zHost = mprintf("cert:%s", pUrlData->name);
339 db_set(zHost, zCert, 1);
340 free(zHost);
341 zHost = mprintf("trusted:%s", pUrlData->name);
342 db_set_int(zHost, trusted, 1);
343 free(zHost);
344 BIO_free(mem);
345 }
346
347 /*
348 ** Get certificate for g.urlName from global config.
349 ** Return NULL if no certificate found.
350 */
351 X509 *ssl_get_certificate(UrlData *pUrlData, int *pTrusted){
352 char *zHost, *zCert;
353 BIO *mem;
354 X509 *cert;
355
356 zHost = mprintf("cert:%s", pUrlData->name);
357 zCert = db_get(zHost, NULL);
358 free(zHost);
359 if ( zCert==NULL )
360 return NULL;
361
362 if ( pTrusted!=0 ){
363 zHost = mprintf("trusted:%s", pUrlData->name);
364 *pTrusted = db_get_int(zHost, 0);
365 free(zHost);
366 }
367
368 mem = BIO_new(BIO_s_mem());
369
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
5252
5353
5454
/*
5555
** Return the current transport error message.
5656
*/
57
-const char *transport_errmsg(void){
57
+const char *transport_errmsg(UrlData *pUrlData){
5858
#ifdef FOSSIL_ENABLE_SSL
59
- if( g.urlIsHttps ){
59
+ if( pUrlData->isHttps ){
6060
return ssl_errmsg();
6161
}
6262
#endif
6363
return socket_errmsg();
6464
}
@@ -86,47 +86,47 @@
8686
#endif
8787
8888
/*
8989
** SSH initialization of the transport layer
9090
*/
91
-int transport_ssh_open(void){
91
+int transport_ssh_open(UrlData *pUrlData){
9292
/* For SSH we need to create and run SSH fossil http
9393
** to talk to the remote machine.
9494
*/
9595
const char *zSsh; /* The base SSH command */
9696
Blob zCmd; /* The SSH command */
9797
char *zHost; /* The host name to contact */
9898
int n; /* Size of prefix string */
9999
100
- socket_ssh_resolve_addr();
100
+ socket_ssh_resolve_addr(pUrlData);
101101
zSsh = db_get("ssh-command", zDefaultSshCmd);
102102
blob_init(&zCmd, zSsh, -1);
103
- if( g.urlPort!=g.urlDfltPort && g.urlPort ){
103
+ if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
104104
#ifdef __MINGW32__
105
- blob_appendf(&zCmd, " -P %d", g.urlPort);
105
+ blob_appendf(&zCmd, " -P %d", pUrlData->port);
106106
#else
107
- blob_appendf(&zCmd, " -p %d", g.urlPort);
107
+ blob_appendf(&zCmd, " -p %d", pUrlData->port);
108108
#endif
109109
}
110110
if( g.fSshTrace ){
111111
fossil_force_newline();
112112
fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113113
}
114
- if( g.urlUser && g.urlUser[0] ){
115
- zHost = mprintf("%s@%s", g.urlUser, g.urlName);
114
+ if( pUrlData->user && pUrlData->user[0] ){
115
+ zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
116116
}else{
117
- zHost = mprintf("%s", g.urlName);
117
+ zHost = mprintf("%s", pUrlData->name);
118118
}
119119
n = blob_size(&zCmd);
120120
blob_append(&zCmd, " ", 1);
121121
shell_escape(&zCmd, zHost);
122122
blob_append(&zCmd, " ", 1);
123
- shell_escape(&zCmd, mprintf("%s", g.urlFossil));
123
+ shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
124124
blob_append(&zCmd, " test-http", 10);
125
- if( g.urlPath && g.urlPath[0] ){
125
+ if( pUrlData->path && pUrlData->path[0] ){
126126
blob_append(&zCmd, " ", 1);
127
- shell_escape(&zCmd, mprintf("%s", g.urlPath));
127
+ shell_escape(&zCmd, mprintf("%s", pUrlData->path));
128128
}
129129
if( g.fSshTrace ){
130130
fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131131
}
132132
free(zHost);
@@ -146,25 +146,25 @@
146146
** g.urlPort TCP/IP port. Ex: 80
147147
** g.urlIsHttps Use TLS for the connection
148148
**
149149
** Return the number of errors.
150150
*/
151
-int transport_open(void){
151
+int transport_open(UrlData *pUrlData){
152152
int rc = 0;
153153
if( transport.isOpen==0 ){
154
- if( g.urlIsSsh ){
155
- rc = transport_ssh_open();
154
+ if( pUrlData->isSsh ){
155
+ rc = transport_ssh_open(pUrlData);
156156
if( rc==0 ) transport.isOpen = 1;
157
- }else if( g.urlIsHttps ){
157
+ }else if( pUrlData->isHttps ){
158158
#ifdef FOSSIL_ENABLE_SSL
159
- rc = ssl_open();
159
+ rc = ssl_open(pUrlData);
160160
if( rc==0 ) transport.isOpen = 1;
161161
#else
162162
socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163163
rc = 1;
164164
#endif
165
- }else if( g.urlIsFile ){
165
+ }else if( pUrlData->isFile ){
166166
sqlite3_uint64 iRandId;
167167
sqlite3_randomness(sizeof(iRandId), &iRandId);
168168
transport.zOutFile = mprintf("%s-%llu-out.http",
169169
g.zRepositoryName, iRandId);
170170
transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173173
if( transport.pFile==0 ){
174174
fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175175
}
176176
transport.isOpen = 1;
177177
}else{
178
- rc = socket_open();
178
+ rc = socket_open(pUrlData);
179179
if( rc==0 ) transport.isOpen = 1;
180180
}
181181
}
182182
return rc;
183183
}
184184
185185
/*
186186
** Close the current connection
187187
*/
188
-void transport_close(void){
188
+void transport_close(UrlData *pUrlData){
189189
if( transport.isOpen ){
190190
free(transport.pBuf);
191191
transport.pBuf = 0;
192192
transport.nAlloc = 0;
193193
transport.nUsed = 0;
@@ -194,17 +194,17 @@
194194
transport.iCursor = 0;
195195
if( transport.pLog ){
196196
fclose(transport.pLog);
197197
transport.pLog = 0;
198198
}
199
- if( g.urlIsSsh ){
199
+ if( pUrlData->isSsh ){
200200
transport_ssh_close();
201
- }else if( g.urlIsHttps ){
201
+ }else if( pUrlData->isHttps ){
202202
#ifdef FOSSIL_ENABLE_SSL
203203
ssl_close();
204204
#endif
205
- }else if( g.urlIsFile ){
205
+ }else if( pUrlData->isFile ){
206206
if( transport.pFile ){
207207
fclose(transport.pFile);
208208
transport.pFile = 0;
209209
}
210210
file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219219
}
220220
221221
/*
222222
** Send content over the wire.
223223
*/
224
-void transport_send(Blob *toSend){
224
+void transport_send(UrlData *pUrlData, Blob *toSend){
225225
char *z = blob_buffer(toSend);
226226
int n = blob_size(toSend);
227227
transport.nSent += n;
228
- if( g.urlIsSsh ){
228
+ if( pUrlData->isSsh ){
229229
fwrite(z, 1, n, sshOut);
230230
fflush(sshOut);
231
- }else if( g.urlIsHttps ){
231
+ }else if( pUrlData->isHttps ){
232232
#ifdef FOSSIL_ENABLE_SSL
233233
int sent;
234234
while( n>0 ){
235235
sent = ssl_send(0, z, n);
236236
/* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237237
if( sent<=0 ) break;
238238
n -= sent;
239239
}
240240
#endif
241
- }else if( g.urlIsFile ){
241
+ }else if( pUrlData->isFile ){
242242
fwrite(z, 1, n, transport.pFile);
243243
}else{
244244
int sent;
245245
while( n>0 ){
246246
sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253253
254254
/*
255255
** This routine is called when the outbound message is complete and
256256
** it is time to being receiving a reply.
257257
*/
258
-void transport_flip(void){
259
- if( g.urlIsFile ){
258
+void transport_flip(UrlData *pUrlData){
259
+ if( pUrlData->isFile ){
260260
char *zCmd;
261261
fclose(transport.pFile);
262262
zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263
- g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
263
+ g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
264264
);
265265
fossil_system(zCmd);
266266
free(zCmd);
267267
transport.pFile = fossil_fopen(transport.zInFile, "rb");
268268
}
@@ -282,21 +282,21 @@
282282
283283
/*
284284
** This routine is called when the inbound message has been received
285285
** and it is time to start sending again.
286286
*/
287
-void transport_rewind(void){
288
- if( g.urlIsFile ){
289
- transport_close();
287
+void transport_rewind(UrlData *pUrlData){
288
+ if( pUrlData->isFile ){
289
+ transport_close(pUrlData);
290290
}
291291
}
292292
293293
/*
294294
** Read N bytes of content directly from the wire and write into
295295
** the buffer.
296296
*/
297
-static int transport_fetch(char *zBuf, int N){
297
+static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
298298
int got;
299299
if( sshIn ){
300300
int x;
301301
int wanted = N;
302302
got = 0;
@@ -304,17 +304,17 @@
304304
x = read(sshIn, &zBuf[got], wanted);
305305
if( x<=0 ) break;
306306
got += x;
307307
wanted -= x;
308308
}
309
- }else if( g.urlIsHttps ){
309
+ }else if( pUrlData->isHttps ){
310310
#ifdef FOSSIL_ENABLE_SSL
311311
got = ssl_receive(0, zBuf, N);
312312
#else
313313
got = 0;
314314
#endif
315
- }else if( g.urlIsFile ){
315
+ }else if( pUrlData->isFile ){
316316
got = fread(zBuf, 1, N, transport.pFile);
317317
}else{
318318
got = socket_receive(0, zBuf, N);
319319
}
320320
/* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327327
328328
/*
329329
** Read N bytes of content from the wire and store in the supplied buffer.
330330
** Return the number of bytes actually received.
331331
*/
332
-int transport_receive(char *zBuf, int N){
332
+int transport_receive(UrlData *pUrlData, char *zBuf, int N){
333333
int onHand; /* Bytes current held in the transport buffer */
334334
int nByte = 0; /* Bytes of content received */
335335
336336
onHand = transport.nUsed - transport.iCursor;
337337
if( g.fSshTrace){
@@ -351,11 +351,11 @@
351351
N -= toMove;
352352
zBuf += toMove;
353353
nByte += toMove;
354354
}
355355
if( N>0 ){
356
- int got = transport_fetch(zBuf, N);
356
+ int got = transport_fetch(pUrlData, zBuf, N);
357357
if( got>0 ){
358358
nByte += got;
359359
transport.nRcvd += got;
360360
}
361361
}
@@ -366,11 +366,11 @@
366366
/*
367367
** Load up to N new bytes of content into the transport.pBuf buffer.
368368
** The buffer itself might be moved. And the transport.iCursor value
369369
** might be reset to 0.
370370
*/
371
-static void transport_load_buffer(int N){
371
+static void transport_load_buffer(UrlData *pUrlData, int N){
372372
int i, j;
373373
if( transport.nAlloc==0 ){
374374
transport.nAlloc = N;
375375
transport.pBuf = fossil_malloc( N );
376376
transport.iCursor = 0;
@@ -388,11 +388,11 @@
388388
transport.nAlloc = transport.nUsed + N;
389389
pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390390
transport.pBuf = pNew;
391391
}
392392
if( N>0 ){
393
- i = transport_fetch(&transport.pBuf[transport.nUsed], N);
393
+ i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
394394
if( i>0 ){
395395
transport.nRcvd += i;
396396
transport.nUsed += i;
397397
}
398398
}
@@ -404,18 +404,18 @@
404404
** from the received line and zero-terminate the result. Return a pointer
405405
** to the line.
406406
**
407407
** Each call to this routine potentially overwrites the returned buffer.
408408
*/
409
-char *transport_receive_line(void){
409
+char *transport_receive_line(UrlData *pUrlData){
410410
int i;
411411
int iStart;
412412
413413
i = iStart = transport.iCursor;
414414
while(1){
415415
if( i >= transport.nUsed ){
416
- transport_load_buffer(g.urlIsSsh ? 2 : 1000);
416
+ transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
417417
i -= iStart;
418418
iStart = 0;
419419
if( i >= transport.nUsed ){
420420
transport.pBuf[i] = 0;
421421
transport.iCursor = i;
@@ -437,15 +437,15 @@
437437
}
438438
439439
/*
440440
** Global transport shutdown
441441
*/
442
-void transport_global_shutdown(void){
443
- if( g.urlIsSsh ){
442
+void transport_global_shutdown(UrlData *pUrlData){
443
+ if( pUrlData->isSsh ){
444444
transport_ssh_close();
445445
}
446
- if( g.urlIsHttps ){
446
+ if( pUrlData->isHttps ){
447447
#ifdef FOSSIL_ENABLE_SSL
448448
ssl_global_shutdown();
449449
#endif
450450
}else{
451451
socket_global_shutdown();
452452
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
52
53
54 /*
55 ** Return the current transport error message.
56 */
57 const char *transport_errmsg(void){
58 #ifdef FOSSIL_ENABLE_SSL
59 if( g.urlIsHttps ){
60 return ssl_errmsg();
61 }
62 #endif
63 return socket_errmsg();
64 }
@@ -86,47 +86,47 @@
86 #endif
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(void){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98 int n; /* Size of prefix string */
99
100 socket_ssh_resolve_addr();
101 zSsh = db_get("ssh-command", zDefaultSshCmd);
102 blob_init(&zCmd, zSsh, -1);
103 if( g.urlPort!=g.urlDfltPort && g.urlPort ){
104 #ifdef __MINGW32__
105 blob_appendf(&zCmd, " -P %d", g.urlPort);
106 #else
107 blob_appendf(&zCmd, " -p %d", g.urlPort);
108 #endif
109 }
110 if( g.fSshTrace ){
111 fossil_force_newline();
112 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113 }
114 if( g.urlUser && g.urlUser[0] ){
115 zHost = mprintf("%s@%s", g.urlUser, g.urlName);
116 }else{
117 zHost = mprintf("%s", g.urlName);
118 }
119 n = blob_size(&zCmd);
120 blob_append(&zCmd, " ", 1);
121 shell_escape(&zCmd, zHost);
122 blob_append(&zCmd, " ", 1);
123 shell_escape(&zCmd, mprintf("%s", g.urlFossil));
124 blob_append(&zCmd, " test-http", 10);
125 if( g.urlPath && g.urlPath[0] ){
126 blob_append(&zCmd, " ", 1);
127 shell_escape(&zCmd, mprintf("%s", g.urlPath));
128 }
129 if( g.fSshTrace ){
130 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131 }
132 free(zHost);
@@ -146,25 +146,25 @@
146 ** g.urlPort TCP/IP port. Ex: 80
147 ** g.urlIsHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(void){
152 int rc = 0;
153 if( transport.isOpen==0 ){
154 if( g.urlIsSsh ){
155 rc = transport_ssh_open();
156 if( rc==0 ) transport.isOpen = 1;
157 }else if( g.urlIsHttps ){
158 #ifdef FOSSIL_ENABLE_SSL
159 rc = ssl_open();
160 if( rc==0 ) transport.isOpen = 1;
161 #else
162 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163 rc = 1;
164 #endif
165 }else if( g.urlIsFile ){
166 sqlite3_uint64 iRandId;
167 sqlite3_randomness(sizeof(iRandId), &iRandId);
168 transport.zOutFile = mprintf("%s-%llu-out.http",
169 g.zRepositoryName, iRandId);
170 transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173 if( transport.pFile==0 ){
174 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175 }
176 transport.isOpen = 1;
177 }else{
178 rc = socket_open();
179 if( rc==0 ) transport.isOpen = 1;
180 }
181 }
182 return rc;
183 }
184
185 /*
186 ** Close the current connection
187 */
188 void transport_close(void){
189 if( transport.isOpen ){
190 free(transport.pBuf);
191 transport.pBuf = 0;
192 transport.nAlloc = 0;
193 transport.nUsed = 0;
@@ -194,17 +194,17 @@
194 transport.iCursor = 0;
195 if( transport.pLog ){
196 fclose(transport.pLog);
197 transport.pLog = 0;
198 }
199 if( g.urlIsSsh ){
200 transport_ssh_close();
201 }else if( g.urlIsHttps ){
202 #ifdef FOSSIL_ENABLE_SSL
203 ssl_close();
204 #endif
205 }else if( g.urlIsFile ){
206 if( transport.pFile ){
207 fclose(transport.pFile);
208 transport.pFile = 0;
209 }
210 file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219 }
220
221 /*
222 ** Send content over the wire.
223 */
224 void transport_send(Blob *toSend){
225 char *z = blob_buffer(toSend);
226 int n = blob_size(toSend);
227 transport.nSent += n;
228 if( g.urlIsSsh ){
229 fwrite(z, 1, n, sshOut);
230 fflush(sshOut);
231 }else if( g.urlIsHttps ){
232 #ifdef FOSSIL_ENABLE_SSL
233 int sent;
234 while( n>0 ){
235 sent = ssl_send(0, z, n);
236 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237 if( sent<=0 ) break;
238 n -= sent;
239 }
240 #endif
241 }else if( g.urlIsFile ){
242 fwrite(z, 1, n, transport.pFile);
243 }else{
244 int sent;
245 while( n>0 ){
246 sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253
254 /*
255 ** This routine is called when the outbound message is complete and
256 ** it is time to being receiving a reply.
257 */
258 void transport_flip(void){
259 if( g.urlIsFile ){
260 char *zCmd;
261 fclose(transport.pFile);
262 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263 g.nameOfExe, g.urlName, transport.zOutFile, transport.zInFile
264 );
265 fossil_system(zCmd);
266 free(zCmd);
267 transport.pFile = fossil_fopen(transport.zInFile, "rb");
268 }
@@ -282,21 +282,21 @@
282
283 /*
284 ** This routine is called when the inbound message has been received
285 ** and it is time to start sending again.
286 */
287 void transport_rewind(void){
288 if( g.urlIsFile ){
289 transport_close();
290 }
291 }
292
293 /*
294 ** Read N bytes of content directly from the wire and write into
295 ** the buffer.
296 */
297 static int transport_fetch(char *zBuf, int N){
298 int got;
299 if( sshIn ){
300 int x;
301 int wanted = N;
302 got = 0;
@@ -304,17 +304,17 @@
304 x = read(sshIn, &zBuf[got], wanted);
305 if( x<=0 ) break;
306 got += x;
307 wanted -= x;
308 }
309 }else if( g.urlIsHttps ){
310 #ifdef FOSSIL_ENABLE_SSL
311 got = ssl_receive(0, zBuf, N);
312 #else
313 got = 0;
314 #endif
315 }else if( g.urlIsFile ){
316 got = fread(zBuf, 1, N, transport.pFile);
317 }else{
318 got = socket_receive(0, zBuf, N);
319 }
320 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327
328 /*
329 ** Read N bytes of content from the wire and store in the supplied buffer.
330 ** Return the number of bytes actually received.
331 */
332 int transport_receive(char *zBuf, int N){
333 int onHand; /* Bytes current held in the transport buffer */
334 int nByte = 0; /* Bytes of content received */
335
336 onHand = transport.nUsed - transport.iCursor;
337 if( g.fSshTrace){
@@ -351,11 +351,11 @@
351 N -= toMove;
352 zBuf += toMove;
353 nByte += toMove;
354 }
355 if( N>0 ){
356 int got = transport_fetch(zBuf, N);
357 if( got>0 ){
358 nByte += got;
359 transport.nRcvd += got;
360 }
361 }
@@ -366,11 +366,11 @@
366 /*
367 ** Load up to N new bytes of content into the transport.pBuf buffer.
368 ** The buffer itself might be moved. And the transport.iCursor value
369 ** might be reset to 0.
370 */
371 static void transport_load_buffer(int N){
372 int i, j;
373 if( transport.nAlloc==0 ){
374 transport.nAlloc = N;
375 transport.pBuf = fossil_malloc( N );
376 transport.iCursor = 0;
@@ -388,11 +388,11 @@
388 transport.nAlloc = transport.nUsed + N;
389 pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390 transport.pBuf = pNew;
391 }
392 if( N>0 ){
393 i = transport_fetch(&transport.pBuf[transport.nUsed], N);
394 if( i>0 ){
395 transport.nRcvd += i;
396 transport.nUsed += i;
397 }
398 }
@@ -404,18 +404,18 @@
404 ** from the received line and zero-terminate the result. Return a pointer
405 ** to the line.
406 **
407 ** Each call to this routine potentially overwrites the returned buffer.
408 */
409 char *transport_receive_line(void){
410 int i;
411 int iStart;
412
413 i = iStart = transport.iCursor;
414 while(1){
415 if( i >= transport.nUsed ){
416 transport_load_buffer(g.urlIsSsh ? 2 : 1000);
417 i -= iStart;
418 iStart = 0;
419 if( i >= transport.nUsed ){
420 transport.pBuf[i] = 0;
421 transport.iCursor = i;
@@ -437,15 +437,15 @@
437 }
438
439 /*
440 ** Global transport shutdown
441 */
442 void transport_global_shutdown(void){
443 if( g.urlIsSsh ){
444 transport_ssh_close();
445 }
446 if( g.urlIsHttps ){
447 #ifdef FOSSIL_ENABLE_SSL
448 ssl_global_shutdown();
449 #endif
450 }else{
451 socket_global_shutdown();
452
--- src/http_transport.c
+++ src/http_transport.c
@@ -52,13 +52,13 @@
52
53
54 /*
55 ** Return the current transport error message.
56 */
57 const char *transport_errmsg(UrlData *pUrlData){
58 #ifdef FOSSIL_ENABLE_SSL
59 if( pUrlData->isHttps ){
60 return ssl_errmsg();
61 }
62 #endif
63 return socket_errmsg();
64 }
@@ -86,47 +86,47 @@
86 #endif
87
88 /*
89 ** SSH initialization of the transport layer
90 */
91 int transport_ssh_open(UrlData *pUrlData){
92 /* For SSH we need to create and run SSH fossil http
93 ** to talk to the remote machine.
94 */
95 const char *zSsh; /* The base SSH command */
96 Blob zCmd; /* The SSH command */
97 char *zHost; /* The host name to contact */
98 int n; /* Size of prefix string */
99
100 socket_ssh_resolve_addr(pUrlData);
101 zSsh = db_get("ssh-command", zDefaultSshCmd);
102 blob_init(&zCmd, zSsh, -1);
103 if( pUrlData->port!=pUrlData->dfltPort && pUrlData->port ){
104 #ifdef __MINGW32__
105 blob_appendf(&zCmd, " -P %d", pUrlData->port);
106 #else
107 blob_appendf(&zCmd, " -p %d", pUrlData->port);
108 #endif
109 }
110 if( g.fSshTrace ){
111 fossil_force_newline();
112 fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */
113 }
114 if( pUrlData->user && pUrlData->user[0] ){
115 zHost = mprintf("%s@%s", pUrlData->user, pUrlData->name);
116 }else{
117 zHost = mprintf("%s", pUrlData->name);
118 }
119 n = blob_size(&zCmd);
120 blob_append(&zCmd, " ", 1);
121 shell_escape(&zCmd, zHost);
122 blob_append(&zCmd, " ", 1);
123 shell_escape(&zCmd, mprintf("%s", pUrlData->fossil));
124 blob_append(&zCmd, " test-http", 10);
125 if( pUrlData->path && pUrlData->path[0] ){
126 blob_append(&zCmd, " ", 1);
127 shell_escape(&zCmd, mprintf("%s", pUrlData->path));
128 }
129 if( g.fSshTrace ){
130 fossil_print("%s\n", blob_str(&zCmd)+n); /* Show tail of SSH command */
131 }
132 free(zHost);
@@ -146,25 +146,25 @@
146 ** g.urlPort TCP/IP port. Ex: 80
147 ** g.urlIsHttps Use TLS for the connection
148 **
149 ** Return the number of errors.
150 */
151 int transport_open(UrlData *pUrlData){
152 int rc = 0;
153 if( transport.isOpen==0 ){
154 if( pUrlData->isSsh ){
155 rc = transport_ssh_open(pUrlData);
156 if( rc==0 ) transport.isOpen = 1;
157 }else if( pUrlData->isHttps ){
158 #ifdef FOSSIL_ENABLE_SSL
159 rc = ssl_open(pUrlData);
160 if( rc==0 ) transport.isOpen = 1;
161 #else
162 socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
163 rc = 1;
164 #endif
165 }else if( pUrlData->isFile ){
166 sqlite3_uint64 iRandId;
167 sqlite3_randomness(sizeof(iRandId), &iRandId);
168 transport.zOutFile = mprintf("%s-%llu-out.http",
169 g.zRepositoryName, iRandId);
170 transport.zInFile = mprintf("%s-%llu-in.http",
@@ -173,21 +173,21 @@
173 if( transport.pFile==0 ){
174 fossil_fatal("cannot output temporary file: %s", transport.zOutFile);
175 }
176 transport.isOpen = 1;
177 }else{
178 rc = socket_open(pUrlData);
179 if( rc==0 ) transport.isOpen = 1;
180 }
181 }
182 return rc;
183 }
184
185 /*
186 ** Close the current connection
187 */
188 void transport_close(UrlData *pUrlData){
189 if( transport.isOpen ){
190 free(transport.pBuf);
191 transport.pBuf = 0;
192 transport.nAlloc = 0;
193 transport.nUsed = 0;
@@ -194,17 +194,17 @@
194 transport.iCursor = 0;
195 if( transport.pLog ){
196 fclose(transport.pLog);
197 transport.pLog = 0;
198 }
199 if( pUrlData->isSsh ){
200 transport_ssh_close();
201 }else if( pUrlData->isHttps ){
202 #ifdef FOSSIL_ENABLE_SSL
203 ssl_close();
204 #endif
205 }else if( pUrlData->isFile ){
206 if( transport.pFile ){
207 fclose(transport.pFile);
208 transport.pFile = 0;
209 }
210 file_delete(transport.zInFile);
@@ -219,28 +219,28 @@
219 }
220
221 /*
222 ** Send content over the wire.
223 */
224 void transport_send(UrlData *pUrlData, Blob *toSend){
225 char *z = blob_buffer(toSend);
226 int n = blob_size(toSend);
227 transport.nSent += n;
228 if( pUrlData->isSsh ){
229 fwrite(z, 1, n, sshOut);
230 fflush(sshOut);
231 }else if( pUrlData->isHttps ){
232 #ifdef FOSSIL_ENABLE_SSL
233 int sent;
234 while( n>0 ){
235 sent = ssl_send(0, z, n);
236 /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
237 if( sent<=0 ) break;
238 n -= sent;
239 }
240 #endif
241 }else if( pUrlData->isFile ){
242 fwrite(z, 1, n, transport.pFile);
243 }else{
244 int sent;
245 while( n>0 ){
246 sent = socket_send(0, z, n);
@@ -253,16 +253,16 @@
253
254 /*
255 ** This routine is called when the outbound message is complete and
256 ** it is time to being receiving a reply.
257 */
258 void transport_flip(UrlData *pUrlData){
259 if( pUrlData->isFile ){
260 char *zCmd;
261 fclose(transport.pFile);
262 zCmd = mprintf("\"%s\" http \"%s\" \"%s\" \"%s\" 127.0.0.1 --localauth",
263 g.nameOfExe, pUrlData->name, transport.zOutFile, transport.zInFile
264 );
265 fossil_system(zCmd);
266 free(zCmd);
267 transport.pFile = fossil_fopen(transport.zInFile, "rb");
268 }
@@ -282,21 +282,21 @@
282
283 /*
284 ** This routine is called when the inbound message has been received
285 ** and it is time to start sending again.
286 */
287 void transport_rewind(UrlData *pUrlData){
288 if( pUrlData->isFile ){
289 transport_close(pUrlData);
290 }
291 }
292
293 /*
294 ** Read N bytes of content directly from the wire and write into
295 ** the buffer.
296 */
297 static int transport_fetch(UrlData *pUrlData, char *zBuf, int N){
298 int got;
299 if( sshIn ){
300 int x;
301 int wanted = N;
302 got = 0;
@@ -304,17 +304,17 @@
304 x = read(sshIn, &zBuf[got], wanted);
305 if( x<=0 ) break;
306 got += x;
307 wanted -= x;
308 }
309 }else if( pUrlData->isHttps ){
310 #ifdef FOSSIL_ENABLE_SSL
311 got = ssl_receive(0, zBuf, N);
312 #else
313 got = 0;
314 #endif
315 }else if( pUrlData->isFile ){
316 got = fread(zBuf, 1, N, transport.pFile);
317 }else{
318 got = socket_receive(0, zBuf, N);
319 }
320 /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -327,11 +327,11 @@
327
328 /*
329 ** Read N bytes of content from the wire and store in the supplied buffer.
330 ** Return the number of bytes actually received.
331 */
332 int transport_receive(UrlData *pUrlData, char *zBuf, int N){
333 int onHand; /* Bytes current held in the transport buffer */
334 int nByte = 0; /* Bytes of content received */
335
336 onHand = transport.nUsed - transport.iCursor;
337 if( g.fSshTrace){
@@ -351,11 +351,11 @@
351 N -= toMove;
352 zBuf += toMove;
353 nByte += toMove;
354 }
355 if( N>0 ){
356 int got = transport_fetch(pUrlData, zBuf, N);
357 if( got>0 ){
358 nByte += got;
359 transport.nRcvd += got;
360 }
361 }
@@ -366,11 +366,11 @@
366 /*
367 ** Load up to N new bytes of content into the transport.pBuf buffer.
368 ** The buffer itself might be moved. And the transport.iCursor value
369 ** might be reset to 0.
370 */
371 static void transport_load_buffer(UrlData *pUrlData, int N){
372 int i, j;
373 if( transport.nAlloc==0 ){
374 transport.nAlloc = N;
375 transport.pBuf = fossil_malloc( N );
376 transport.iCursor = 0;
@@ -388,11 +388,11 @@
388 transport.nAlloc = transport.nUsed + N;
389 pNew = fossil_realloc(transport.pBuf, transport.nAlloc);
390 transport.pBuf = pNew;
391 }
392 if( N>0 ){
393 i = transport_fetch(pUrlData, &transport.pBuf[transport.nUsed], N);
394 if( i>0 ){
395 transport.nRcvd += i;
396 transport.nUsed += i;
397 }
398 }
@@ -404,18 +404,18 @@
404 ** from the received line and zero-terminate the result. Return a pointer
405 ** to the line.
406 **
407 ** Each call to this routine potentially overwrites the returned buffer.
408 */
409 char *transport_receive_line(UrlData *pUrlData){
410 int i;
411 int iStart;
412
413 i = iStart = transport.iCursor;
414 while(1){
415 if( i >= transport.nUsed ){
416 transport_load_buffer(pUrlData, pUrlData->isSsh ? 2 : 1000);
417 i -= iStart;
418 iStart = 0;
419 if( i >= transport.nUsed ){
420 transport.pBuf[i] = 0;
421 transport.iCursor = i;
@@ -437,15 +437,15 @@
437 }
438
439 /*
440 ** Global transport shutdown
441 */
442 void transport_global_shutdown(UrlData *pUrlData){
443 if( pUrlData->isSsh ){
444 transport_ssh_close();
445 }
446 if( pUrlData->isHttps ){
447 #ifdef FOSSIL_ENABLE_SSL
448 ssl_global_shutdown();
449 #endif
450 }else{
451 socket_global_shutdown();
452
+6
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114114
#endif
115115
116116
/*
117117
** All global variables are in this structure.
118118
*/
119
+#define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
+
119121
struct Global {
120122
int argc; char **argv; /* Command-line arguments to the program */
121123
char *nameOfExe; /* Full path of executable. */
122124
const char *zErrlog; /* Log errors to this file, if not NULL */
123125
int isConst; /* True if the output is unchanging */
@@ -167,10 +169,14 @@
167169
int wikiFlags; /* Wiki conversion flags applied to %w and %W */
168170
char isHTTP; /* True if server/CGI modes, else assume CLI. */
169171
char javascriptHyperlink; /* If true, set href= using script, not HTML */
170172
Blob httpHeader; /* Complete text of the HTTP request header */
171173
174
+ /*
175
+ ** NOTE: These members MUST be kept in sync with those in the "UrlData"
176
+ ** structure defined in "url.c".
177
+ */
172178
int urlIsFile; /* True if a "file:" url */
173179
int urlIsHttps; /* True if a "https:" url */
174180
int urlIsSsh; /* True if an "ssh:" url */
175181
char *urlName; /* Hostname for http: or filename for file: */
176182
char *urlHostname; /* The HOST: parameter on http headers */
177183
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
 
 
119 struct Global {
120 int argc; char **argv; /* Command-line arguments to the program */
121 char *nameOfExe; /* Full path of executable. */
122 const char *zErrlog; /* Log errors to this file, if not NULL */
123 int isConst; /* True if the output is unchanging */
@@ -167,10 +169,14 @@
167 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
168 char isHTTP; /* True if server/CGI modes, else assume CLI. */
169 char javascriptHyperlink; /* If true, set href= using script, not HTML */
170 Blob httpHeader; /* Complete text of the HTTP request header */
171
 
 
 
 
172 int urlIsFile; /* True if a "file:" url */
173 int urlIsHttps; /* True if a "https:" url */
174 int urlIsSsh; /* True if an "ssh:" url */
175 char *urlName; /* Hostname for http: or filename for file: */
176 char *urlHostname; /* The HOST: parameter on http headers */
177
--- src/main.c
+++ src/main.c
@@ -114,10 +114,12 @@
114 #endif
115
116 /*
117 ** All global variables are in this structure.
118 */
119 #define GLOBAL_URL() ((UrlData *)(&g.urlIsFile))
120
121 struct Global {
122 int argc; char **argv; /* Command-line arguments to the program */
123 char *nameOfExe; /* Full path of executable. */
124 const char *zErrlog; /* Log errors to this file, if not NULL */
125 int isConst; /* True if the output is unchanging */
@@ -167,10 +169,14 @@
169 int wikiFlags; /* Wiki conversion flags applied to %w and %W */
170 char isHTTP; /* True if server/CGI modes, else assume CLI. */
171 char javascriptHyperlink; /* If true, set href= using script, not HTML */
172 Blob httpHeader; /* Complete text of the HTTP request header */
173
174 /*
175 ** NOTE: These members MUST be kept in sync with those in the "UrlData"
176 ** structure defined in "url.c".
177 */
178 int urlIsFile; /* True if a "file:" url */
179 int urlIsHttps; /* True if a "https:" url */
180 int urlIsSsh; /* True if an "ssh:" url */
181 char *urlName; /* Hostname for http: or filename for file: */
182 char *urlHostname; /* The HOST: parameter on http headers */
183
+16 -16
--- src/th_main.c
+++ src/th_main.c
@@ -847,10 +847,11 @@
847847
int *argl
848848
){
849849
const char *zSep, *zType, *zRegexp, *zParams;
850850
Blob header, payload;
851851
ReCompiled *pRe = 0;
852
+ UrlData urlData;
852853
853854
if( argc>1 && fossil_strnicmp(argv[1], "-asynchronous\0", 14) ){
854855
Th_ErrorMessage(interp,
855856
"synchronous http requests not yet implemented", 0, 0);
856857
return TH_ERROR;
@@ -865,12 +866,12 @@
865866
zType = "POST";
866867
}else{
867868
zType = "GET";
868869
}
869870
zParams = strrchr(argv[1], '?');
870
- url_parse(argv[1], 0);
871
- if( g.urlIsSsh || g.urlIsFile ){
871
+ url_parse_local(argv[1], 0, &urlData);
872
+ if( urlData.isSsh || urlData.isFile ){
872873
Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
873874
return TH_ERROR;
874875
}
875876
zRegexp = db_get("th1-uri-regexp", 0);
876877
if( zRegexp && zRegexp[0] ){
@@ -878,47 +879,46 @@
878879
if( zErr ){
879880
Th_SetResult(interp, zErr, -1);
880881
return TH_ERROR;
881882
}
882883
}
883
- if( !re_match(pRe, (const unsigned char *)g.urlCanonical, -1) ){
884
+ if( !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
884885
Th_SetResult(interp, "url not allowed", -1);
885886
re_free(pRe);
886887
return TH_ERROR;
887888
}
888889
re_free(pRe);
889
- if( transport_open() ){
890
- Th_ErrorMessage(interp, transport_errmsg(), 0, 0);
890
+ if( transport_open(&urlData) ){
891
+ Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
891892
return TH_ERROR;
892893
}
893894
blob_zero(&header);
894
- if( strlen(g.urlPath)>0 && zParams!=argv[1] ){
895
+ if( strlen(urlData.path)>0 && zParams!=argv[1] ){
895896
zSep = "";
896897
}else{
897898
zSep = "/";
898899
}
899900
blob_appendf(&header, "%s %s%s%s HTTP/1.0\r\n",
900
- zType, zSep, g.urlPath, zParams ? zParams : "");
901
- if( g.urlProxyAuth ){
902
- blob_appendf(&header, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
901
+ zType, zSep, urlData.path, zParams ? zParams : "");
902
+ if( urlData.proxyAuth ){
903
+ blob_appendf(&header, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
903904
}
904
- if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){
905
- char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
905
+ if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
906
+ char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
906907
char *zEncoded = encode64(zCredentials, -1);
907908
blob_appendf(&header, "Authorization: Basic %s\r\n", zEncoded);
908909
fossil_free(zEncoded);
909910
fossil_free(zCredentials);
910911
}
911
- blob_appendf(&header, "Host: %s\r\n", g.urlHostname);
912
+ blob_appendf(&header, "Host: %s\r\n", urlData.hostname);
912913
blob_appendf(&header, "User-Agent: Fossil/" RELEASE_VERSION
913914
" (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
914915
blob_appendf(&header, "Content-Type: text/plain\r\n");
915916
blob_appendf(&header, "Content-Length: %d\r\n\r\n", blob_size(&payload));
916
- transport_send(&header);
917
- transport_send(&payload);
918
- transport_close();
919
- g.urlProtocol = 0; /* Make sure the parsed URL is not reused. */
917
+ transport_send(&urlData, &header);
918
+ transport_send(&urlData, &payload);
919
+ transport_close(&urlData);
920920
Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results yet. */
921921
return TH_OK;
922922
}
923923
924924
/*
925925
--- src/th_main.c
+++ src/th_main.c
@@ -847,10 +847,11 @@
847 int *argl
848 ){
849 const char *zSep, *zType, *zRegexp, *zParams;
850 Blob header, payload;
851 ReCompiled *pRe = 0;
 
852
853 if( argc>1 && fossil_strnicmp(argv[1], "-asynchronous\0", 14) ){
854 Th_ErrorMessage(interp,
855 "synchronous http requests not yet implemented", 0, 0);
856 return TH_ERROR;
@@ -865,12 +866,12 @@
865 zType = "POST";
866 }else{
867 zType = "GET";
868 }
869 zParams = strrchr(argv[1], '?');
870 url_parse(argv[1], 0);
871 if( g.urlIsSsh || g.urlIsFile ){
872 Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
873 return TH_ERROR;
874 }
875 zRegexp = db_get("th1-uri-regexp", 0);
876 if( zRegexp && zRegexp[0] ){
@@ -878,47 +879,46 @@
878 if( zErr ){
879 Th_SetResult(interp, zErr, -1);
880 return TH_ERROR;
881 }
882 }
883 if( !re_match(pRe, (const unsigned char *)g.urlCanonical, -1) ){
884 Th_SetResult(interp, "url not allowed", -1);
885 re_free(pRe);
886 return TH_ERROR;
887 }
888 re_free(pRe);
889 if( transport_open() ){
890 Th_ErrorMessage(interp, transport_errmsg(), 0, 0);
891 return TH_ERROR;
892 }
893 blob_zero(&header);
894 if( strlen(g.urlPath)>0 && zParams!=argv[1] ){
895 zSep = "";
896 }else{
897 zSep = "/";
898 }
899 blob_appendf(&header, "%s %s%s%s HTTP/1.0\r\n",
900 zType, zSep, g.urlPath, zParams ? zParams : "");
901 if( g.urlProxyAuth ){
902 blob_appendf(&header, "Proxy-Authorization: %s\r\n", g.urlProxyAuth);
903 }
904 if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){
905 char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]);
906 char *zEncoded = encode64(zCredentials, -1);
907 blob_appendf(&header, "Authorization: Basic %s\r\n", zEncoded);
908 fossil_free(zEncoded);
909 fossil_free(zCredentials);
910 }
911 blob_appendf(&header, "Host: %s\r\n", g.urlHostname);
912 blob_appendf(&header, "User-Agent: Fossil/" RELEASE_VERSION
913 " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
914 blob_appendf(&header, "Content-Type: text/plain\r\n");
915 blob_appendf(&header, "Content-Length: %d\r\n\r\n", blob_size(&payload));
916 transport_send(&header);
917 transport_send(&payload);
918 transport_close();
919 g.urlProtocol = 0; /* Make sure the parsed URL is not reused. */
920 Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results yet. */
921 return TH_OK;
922 }
923
924 /*
925
--- src/th_main.c
+++ src/th_main.c
@@ -847,10 +847,11 @@
847 int *argl
848 ){
849 const char *zSep, *zType, *zRegexp, *zParams;
850 Blob header, payload;
851 ReCompiled *pRe = 0;
852 UrlData urlData;
853
854 if( argc>1 && fossil_strnicmp(argv[1], "-asynchronous\0", 14) ){
855 Th_ErrorMessage(interp,
856 "synchronous http requests not yet implemented", 0, 0);
857 return TH_ERROR;
@@ -865,12 +866,12 @@
866 zType = "POST";
867 }else{
868 zType = "GET";
869 }
870 zParams = strrchr(argv[1], '?');
871 url_parse_local(argv[1], 0, &urlData);
872 if( urlData.isSsh || urlData.isFile ){
873 Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0);
874 return TH_ERROR;
875 }
876 zRegexp = db_get("th1-uri-regexp", 0);
877 if( zRegexp && zRegexp[0] ){
@@ -878,47 +879,46 @@
879 if( zErr ){
880 Th_SetResult(interp, zErr, -1);
881 return TH_ERROR;
882 }
883 }
884 if( !re_match(pRe, (const unsigned char *)urlData.canonical, -1) ){
885 Th_SetResult(interp, "url not allowed", -1);
886 re_free(pRe);
887 return TH_ERROR;
888 }
889 re_free(pRe);
890 if( transport_open(&urlData) ){
891 Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0);
892 return TH_ERROR;
893 }
894 blob_zero(&header);
895 if( strlen(urlData.path)>0 && zParams!=argv[1] ){
896 zSep = "";
897 }else{
898 zSep = "/";
899 }
900 blob_appendf(&header, "%s %s%s%s HTTP/1.0\r\n",
901 zType, zSep, urlData.path, zParams ? zParams : "");
902 if( urlData.proxyAuth ){
903 blob_appendf(&header, "Proxy-Authorization: %s\r\n", urlData.proxyAuth);
904 }
905 if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){
906 char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]);
907 char *zEncoded = encode64(zCredentials, -1);
908 blob_appendf(&header, "Authorization: Basic %s\r\n", zEncoded);
909 fossil_free(zEncoded);
910 fossil_free(zCredentials);
911 }
912 blob_appendf(&header, "Host: %s\r\n", urlData.hostname);
913 blob_appendf(&header, "User-Agent: Fossil/" RELEASE_VERSION
914 " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n");
915 blob_appendf(&header, "Content-Type: text/plain\r\n");
916 blob_appendf(&header, "Content-Length: %d\r\n\r\n", blob_size(&payload));
917 transport_send(&urlData, &header);
918 transport_send(&urlData, &payload);
919 transport_close(&urlData);
 
920 Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results yet. */
921 return TH_OK;
922 }
923
924 /*
925
+247 -179
--- src/url.c
+++ src/url.c
@@ -28,10 +28,34 @@
2828
#define URL_REMEMBER 0x002 /* Remember the url for later reuse */
2929
#define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
3030
#define URL_REMEMBER_PW 0x008 /* Should remember pw */
3131
#define URL_PROMPTED 0x010 /* Prompted for PW already */
3232
33
+/*
34
+** The URL related data used with this subsystem.
35
+*/
36
+struct UrlData {
37
+ /*
38
+ ** NOTE: These members MUST be kept in sync with the related ones in the
39
+ ** "Global" structure defined in "main.c".
40
+ */
41
+ int isFile; /* True if a "file:" url */
42
+ int isHttps; /* True if a "https:" url */
43
+ int isSsh; /* True if an "ssh:" url */
44
+ char *name; /* Hostname for http: or filename for file: */
45
+ char *hostname; /* The HOST: parameter on http headers */
46
+ char *protocol; /* "http" or "https" */
47
+ int port; /* TCP port number for http: or https: */
48
+ int dfltPort; /* The default port for the given protocol */
49
+ char *path; /* Pathname for http: */
50
+ char *user; /* User id for http: */
51
+ char *passwd; /* Password for http: */
52
+ char *canonical; /* Canonical representation of the URL */
53
+ char *proxyAuth; /* Proxy-Authorizer: string */
54
+ char *fossil; /* The fossil query parameter on ssh: */
55
+ unsigned flags; /* Boolean flags controlling URL processing */
56
+};
3357
#endif /* INTERFACE */
3458
3559
3660
/*
3761
** Convert a string to lower-case.
@@ -40,10 +64,203 @@
4064
while( *z ){
4165
*z = fossil_tolower(*z);
4266
z++;
4367
}
4468
}
69
+
70
+/*
71
+** Parse the given URL. Populate members of the provided UrlData structure
72
+** as follows:
73
+**
74
+** isFile True if FILE:
75
+** isHttps True if HTTPS:
76
+** isSsh True if SSH:
77
+** protocol "http" or "https" or "file"
78
+** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
79
+** port TCP port number for HTTP or HTTPS.
80
+** dfltPort Default TCP port number (80 or 443).
81
+** path Path name for HTTP or HTTPS.
82
+** user Userid.
83
+** passwd Password.
84
+** hostname HOST:PORT or just HOST if port is the default.
85
+** canonical The URL in canonical form, omitting the password
86
+**
87
+*/
88
+void url_parse_local(
89
+ const char *zUrl,
90
+ unsigned int urlFlags,
91
+ UrlData *pUrlData
92
+){
93
+ int i, j, c;
94
+ char *zFile = 0;
95
+ int bPrompted = 0;
96
+ int bSetUrl = 1;
97
+
98
+ memset(pUrlData, 0, sizeof(UrlData));
99
+
100
+ if( zUrl==0 ){
101
+ zUrl = db_get("last-sync-url", 0);
102
+ if( zUrl==0 ) return;
103
+ pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
104
+ bSetUrl = 0;
105
+ }
106
+
107
+ if( strncmp(zUrl, "http://", 7)==0
108
+ || strncmp(zUrl, "https://", 8)==0
109
+ || strncmp(zUrl, "ssh://", 6)==0
110
+ ){
111
+ int iStart;
112
+ char *zLogin;
113
+ char *zExe;
114
+ char cQuerySep = '?';
115
+
116
+ pUrlData->isFile = 0;
117
+ if( zUrl[4]=='s' ){
118
+ pUrlData->isHttps = 1;
119
+ pUrlData->protocol = "https";
120
+ pUrlData->dfltPort = 443;
121
+ iStart = 8;
122
+ }else if( zUrl[0]=='s' ){
123
+ pUrlData->isSsh = 1;
124
+ pUrlData->protocol = "ssh";
125
+ pUrlData->dfltPort = 22;
126
+ pUrlData->fossil = "fossil";
127
+ iStart = 6;
128
+ }else{
129
+ pUrlData->isHttps = 0;
130
+ pUrlData->protocol = "http";
131
+ pUrlData->dfltPort = 80;
132
+ iStart = 7;
133
+ }
134
+ for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
135
+ if( c=='@' ){
136
+ /* Parse up the user-id and password */
137
+ for(j=iStart; j<i && zUrl[j]!=':'; j++){}
138
+ pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
139
+ dehttpize(pUrlData->user);
140
+ if( j<i ){
141
+ pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
142
+ dehttpize(pUrlData->passwd);
143
+ }
144
+ if( pUrlData->isSsh && pUrlData->passwd ){
145
+ zLogin = mprintf("%t:*@", pUrlData->user);
146
+ }else{
147
+ zLogin = mprintf("%t@", pUrlData->user);
148
+ }
149
+ for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
150
+ pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
151
+ i = j;
152
+ }else{
153
+ for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
154
+ pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
155
+ zLogin = mprintf("");
156
+ }
157
+ url_tolower(pUrlData->name);
158
+ if( c==':' ){
159
+ pUrlData->port = 0;
160
+ i++;
161
+ while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
162
+ pUrlData->port = pUrlData->port*10 + c - '0';
163
+ i++;
164
+ }
165
+ pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
166
+ }else{
167
+ pUrlData->port = pUrlData->dfltPort;
168
+ pUrlData->hostname = pUrlData->name;
169
+ }
170
+ dehttpize(pUrlData->name);
171
+ pUrlData->path = mprintf("%s", &zUrl[i]);
172
+ for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
173
+ if( pUrlData->path[i] ){
174
+ pUrlData->path[i] = 0;
175
+ i++;
176
+ }
177
+ zExe = mprintf("");
178
+ while( pUrlData->path[i]!=0 ){
179
+ char *zName, *zValue;
180
+ zName = &pUrlData->path[i];
181
+ zValue = zName;
182
+ while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
183
+ if( pUrlData->path[i]=='=' ){
184
+ pUrlData->path[i] = 0;
185
+ i++;
186
+ zValue = &pUrlData->path[i];
187
+ while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
188
+ }
189
+ if( pUrlData->path[i] ){
190
+ pUrlData->path[i] = 0;
191
+ i++;
192
+ }
193
+ if( fossil_strcmp(zName,"fossil")==0 ){
194
+ pUrlData->fossil = zValue;
195
+ dehttpize(pUrlData->fossil);
196
+ zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
197
+ cQuerySep = '&';
198
+ }
199
+ }
200
+
201
+ dehttpize(pUrlData->path);
202
+ if( pUrlData->dfltPort==pUrlData->port ){
203
+ pUrlData->canonical = mprintf(
204
+ "%s://%s%T%T%s",
205
+ pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
206
+ );
207
+ }else{
208
+ pUrlData->canonical = mprintf(
209
+ "%s://%s%T:%d%T%s",
210
+ pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
211
+ pUrlData->path, zExe
212
+ );
213
+ }
214
+ if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
215
+ free(zLogin);
216
+ }else if( strncmp(zUrl, "file:", 5)==0 ){
217
+ pUrlData->isFile = 1;
218
+ if( zUrl[5]=='/' && zUrl[6]=='/' ){
219
+ i = 7;
220
+ }else{
221
+ i = 5;
222
+ }
223
+ zFile = mprintf("%s", &zUrl[i]);
224
+ }else if( file_isfile(zUrl) ){
225
+ pUrlData->isFile = 1;
226
+ zFile = mprintf("%s", zUrl);
227
+ }else if( file_isdir(zUrl)==1 ){
228
+ zFile = mprintf("%s/FOSSIL", zUrl);
229
+ if( file_isfile(zFile) ){
230
+ pUrlData->isFile = 1;
231
+ }else{
232
+ free(zFile);
233
+ fossil_fatal("unknown repository: %s", zUrl);
234
+ }
235
+ }else{
236
+ fossil_fatal("unknown repository: %s", zUrl);
237
+ }
238
+ pUrlData->flags = urlFlags;
239
+ if( pUrlData->isFile ){
240
+ Blob cfile;
241
+ dehttpize(zFile);
242
+ file_canonical_name(zFile, &cfile, 0);
243
+ free(zFile);
244
+ pUrlData->protocol = "file";
245
+ pUrlData->path = "";
246
+ pUrlData->name = mprintf("%b", &cfile);
247
+ pUrlData->canonical = mprintf("file://%T", pUrlData->name);
248
+ blob_reset(&cfile);
249
+ }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
250
+ url_prompt_for_password();
251
+ bPrompted = 1;
252
+ }
253
+ if( urlFlags & URL_REMEMBER ){
254
+ if( bSetUrl ){
255
+ db_set("last-sync-url", pUrlData->canonical, 0);
256
+ }
257
+ if( !bPrompted && pUrlData->passwd && pUrlData->user ){
258
+ db_set("last-sync-pw", obscure(pUrlData->passwd), 0);
259
+ }
260
+ }
261
+}
45262
46263
/*
47264
** Parse the given URL, which describes a sync server. Populate variables
48265
** in the global "g" structure as follows:
49266
**
@@ -68,175 +285,14 @@
68285
**
69286
** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
70287
**
71288
*/
72289
void url_parse(const char *zUrl, unsigned int urlFlags){
73
- int i, j, c;
74
- char *zFile = 0;
75
- int bPrompted = 0;
76
- int bSetUrl = 1;
77
-
78
- if( zUrl==0 ){
79
- zUrl = db_get("last-sync-url", 0);
80
- if( zUrl==0 ) return;
81
- g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
82
- bSetUrl = 0;
83
- }
84
-
85
- if( strncmp(zUrl, "http://", 7)==0
86
- || strncmp(zUrl, "https://", 8)==0
87
- || strncmp(zUrl, "ssh://", 6)==0
88
- ){
89
- int iStart;
90
- char *zLogin;
91
- char *zExe;
92
- char cQuerySep = '?';
93
-
94
- g.urlIsFile = 0;
95
- if( zUrl[4]=='s' ){
96
- g.urlIsHttps = 1;
97
- g.urlProtocol = "https";
98
- g.urlDfltPort = 443;
99
- iStart = 8;
100
- }else if( zUrl[0]=='s' ){
101
- g.urlIsSsh = 1;
102
- g.urlProtocol = "ssh";
103
- g.urlDfltPort = 22;
104
- g.urlFossil = "fossil";
105
- iStart = 6;
106
- }else{
107
- g.urlIsHttps = 0;
108
- g.urlProtocol = "http";
109
- g.urlDfltPort = 80;
110
- iStart = 7;
111
- }
112
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
113
- if( c=='@' ){
114
- /* Parse up the user-id and password */
115
- for(j=iStart; j<i && zUrl[j]!=':'; j++){}
116
- g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
117
- dehttpize(g.urlUser);
118
- if( j<i ){
119
- g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
120
- dehttpize(g.urlPasswd);
121
- }
122
- if( g.urlIsSsh && g.urlPasswd ){
123
- zLogin = mprintf("%t:*@", g.urlUser);
124
- }else{
125
- zLogin = mprintf("%t@", g.urlUser);
126
- }
127
- for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
128
- g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
129
- i = j;
130
- }else{
131
- for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
132
- g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
133
- zLogin = mprintf("");
134
- }
135
- url_tolower(g.urlName);
136
- if( c==':' ){
137
- g.urlPort = 0;
138
- i++;
139
- while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
140
- g.urlPort = g.urlPort*10 + c - '0';
141
- i++;
142
- }
143
- g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
144
- }else{
145
- g.urlPort = g.urlDfltPort;
146
- g.urlHostname = g.urlName;
147
- }
148
- dehttpize(g.urlName);
149
- g.urlPath = mprintf("%s", &zUrl[i]);
150
- for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
151
- if( g.urlPath[i] ){
152
- g.urlPath[i] = 0;
153
- i++;
154
- }
155
- zExe = mprintf("");
156
- while( g.urlPath[i]!=0 ){
157
- char *zName, *zValue;
158
- zName = &g.urlPath[i];
159
- zValue = zName;
160
- while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
161
- if( g.urlPath[i]=='=' ){
162
- g.urlPath[i] = 0;
163
- i++;
164
- zValue = &g.urlPath[i];
165
- while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
166
- }
167
- if( g.urlPath[i] ){
168
- g.urlPath[i] = 0;
169
- i++;
170
- }
171
- if( fossil_strcmp(zName,"fossil")==0 ){
172
- g.urlFossil = zValue;
173
- dehttpize(g.urlFossil);
174
- zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
175
- cQuerySep = '&';
176
- }
177
- }
178
-
179
- dehttpize(g.urlPath);
180
- if( g.urlDfltPort==g.urlPort ){
181
- g.urlCanonical = mprintf(
182
- "%s://%s%T%T%s",
183
- g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
184
- );
185
- }else{
186
- g.urlCanonical = mprintf(
187
- "%s://%s%T:%d%T%s",
188
- g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
189
- );
190
- }
191
- if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
192
- free(zLogin);
193
- }else if( strncmp(zUrl, "file:", 5)==0 ){
194
- g.urlIsFile = 1;
195
- if( zUrl[5]=='/' && zUrl[6]=='/' ){
196
- i = 7;
197
- }else{
198
- i = 5;
199
- }
200
- zFile = mprintf("%s", &zUrl[i]);
201
- }else if( file_isfile(zUrl) ){
202
- g.urlIsFile = 1;
203
- zFile = mprintf("%s", zUrl);
204
- }else if( file_isdir(zUrl)==1 ){
205
- zFile = mprintf("%s/FOSSIL", zUrl);
206
- if( file_isfile(zFile) ){
207
- g.urlIsFile = 1;
208
- }else{
209
- free(zFile);
210
- fossil_fatal("unknown repository: %s", zUrl);
211
- }
212
- }else{
213
- fossil_fatal("unknown repository: %s", zUrl);
214
- }
215
- g.urlFlags = urlFlags;
216
- if( g.urlIsFile ){
217
- Blob cfile;
218
- dehttpize(zFile);
219
- file_canonical_name(zFile, &cfile, 0);
220
- free(zFile);
221
- g.urlProtocol = "file";
222
- g.urlPath = "";
223
- g.urlName = mprintf("%b", &cfile);
224
- g.urlCanonical = mprintf("file://%T", g.urlName);
225
- blob_reset(&cfile);
226
- }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
227
- url_prompt_for_password();
228
- bPrompted = 1;
229
- }
230
- if( urlFlags & URL_REMEMBER ){
231
- if( bSetUrl ){
232
- db_set("last-sync-url", g.urlCanonical, 0);
233
- }
234
- if( !bPrompted && g.urlPasswd && g.urlUser ){
235
- db_set("last-sync-pw", obscure(g.urlPasswd), 0);
236
- }
237
- }
290
+ UrlData urlData;
291
+ memcpy(&urlData, GLOBAL_URL(), sizeof(UrlData));
292
+ url_parse_local(zUrl, urlFlags, &urlData);
293
+ memcpy(GLOBAL_URL(), &urlData, sizeof(UrlData));
238294
}
239295
240296
/*
241297
** COMMAND: test-urlparser
242298
**
@@ -428,36 +484,48 @@
428484
}
429485
return blob_str(&p->url);
430486
}
431487
432488
/*
433
-** Prompt the user for the password for g.urlUser. Store the result
434
-** in g.urlPasswd.
489
+** Prompt the user for the password that corresponds to the "user" member of
490
+** the provided UrlData structure. Store the result into the "passwd" member
491
+** of the provided UrlData structure.
435492
*/
436
-void url_prompt_for_password(void){
437
- if( g.urlIsSsh || g.urlIsFile ) return;
493
+void url_prompt_for_password_local(UrlData *pUrlData){
494
+ if( pUrlData->isSsh || pUrlData->isFile ) return;
438495
if( isatty(fileno(stdin))
439
- && (g.urlFlags & URL_PROMPT_PW)!=0
440
- && (g.urlFlags & URL_PROMPTED)==0
496
+ && (pUrlData->flags & URL_PROMPT_PW)!=0
497
+ && (pUrlData->flags & URL_PROMPTED)==0
441498
){
442
- g.urlFlags |= URL_PROMPTED;
443
- g.urlPasswd = prompt_for_user_password(g.urlUser);
444
- if( g.urlPasswd[0]
445
- && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
499
+ pUrlData->flags |= URL_PROMPTED;
500
+ pUrlData->passwd = prompt_for_user_password(pUrlData->user);
501
+ if( pUrlData->passwd[0]
502
+ && (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
446503
){
447504
if( save_password_prompt() ){
448
- g.urlFlags |= URL_REMEMBER_PW;
449
- if( g.urlFlags & URL_REMEMBER ){
450
- db_set("last-sync-pw", obscure(g.urlPasswd), 0);
505
+ pUrlData->flags |= URL_REMEMBER_PW;
506
+ if( pUrlData->flags & URL_REMEMBER ){
507
+ db_set("last-sync-pw", obscure(pUrlData->passwd), 0);
451508
}
452509
}
453510
}
454511
}else{
455512
fossil_fatal("missing or incorrect password for user \"%s\"",
456
- g.urlUser);
513
+ pUrlData->user);
457514
}
458515
}
516
+
517
+/*
518
+** Prompt the user for the password for g.urlUser. Store the result
519
+** in g.urlPasswd.
520
+*/
521
+void url_prompt_for_password(void){
522
+ UrlData urlData;
523
+ memcpy(&urlData, GLOBAL_URL(), sizeof(UrlData));
524
+ url_prompt_for_password_local(&urlData);
525
+ memcpy(GLOBAL_URL(), &urlData, sizeof(UrlData));
526
+}
459527
460528
/*
461529
** Remember the URL if requested.
462530
*/
463531
void url_remember(void){
464532
--- src/url.c
+++ src/url.c
@@ -28,10 +28,34 @@
28 #define URL_REMEMBER 0x002 /* Remember the url for later reuse */
29 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
30 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
31 #define URL_PROMPTED 0x010 /* Prompted for PW already */
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33 #endif /* INTERFACE */
34
35
36 /*
37 ** Convert a string to lower-case.
@@ -40,10 +64,203 @@
40 while( *z ){
41 *z = fossil_tolower(*z);
42 z++;
43 }
44 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
46 /*
47 ** Parse the given URL, which describes a sync server. Populate variables
48 ** in the global "g" structure as follows:
49 **
@@ -68,175 +285,14 @@
68 **
69 ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
70 **
71 */
72 void url_parse(const char *zUrl, unsigned int urlFlags){
73 int i, j, c;
74 char *zFile = 0;
75 int bPrompted = 0;
76 int bSetUrl = 1;
77
78 if( zUrl==0 ){
79 zUrl = db_get("last-sync-url", 0);
80 if( zUrl==0 ) return;
81 g.urlPasswd = unobscure(db_get("last-sync-pw", 0));
82 bSetUrl = 0;
83 }
84
85 if( strncmp(zUrl, "http://", 7)==0
86 || strncmp(zUrl, "https://", 8)==0
87 || strncmp(zUrl, "ssh://", 6)==0
88 ){
89 int iStart;
90 char *zLogin;
91 char *zExe;
92 char cQuerySep = '?';
93
94 g.urlIsFile = 0;
95 if( zUrl[4]=='s' ){
96 g.urlIsHttps = 1;
97 g.urlProtocol = "https";
98 g.urlDfltPort = 443;
99 iStart = 8;
100 }else if( zUrl[0]=='s' ){
101 g.urlIsSsh = 1;
102 g.urlProtocol = "ssh";
103 g.urlDfltPort = 22;
104 g.urlFossil = "fossil";
105 iStart = 6;
106 }else{
107 g.urlIsHttps = 0;
108 g.urlProtocol = "http";
109 g.urlDfltPort = 80;
110 iStart = 7;
111 }
112 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
113 if( c=='@' ){
114 /* Parse up the user-id and password */
115 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
116 g.urlUser = mprintf("%.*s", j-iStart, &zUrl[iStart]);
117 dehttpize(g.urlUser);
118 if( j<i ){
119 g.urlPasswd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
120 dehttpize(g.urlPasswd);
121 }
122 if( g.urlIsSsh && g.urlPasswd ){
123 zLogin = mprintf("%t:*@", g.urlUser);
124 }else{
125 zLogin = mprintf("%t@", g.urlUser);
126 }
127 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
128 g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]);
129 i = j;
130 }else{
131 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
132 g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]);
133 zLogin = mprintf("");
134 }
135 url_tolower(g.urlName);
136 if( c==':' ){
137 g.urlPort = 0;
138 i++;
139 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
140 g.urlPort = g.urlPort*10 + c - '0';
141 i++;
142 }
143 g.urlHostname = mprintf("%s:%d", g.urlName, g.urlPort);
144 }else{
145 g.urlPort = g.urlDfltPort;
146 g.urlHostname = g.urlName;
147 }
148 dehttpize(g.urlName);
149 g.urlPath = mprintf("%s", &zUrl[i]);
150 for(i=0; g.urlPath[i] && g.urlPath[i]!='?'; i++){}
151 if( g.urlPath[i] ){
152 g.urlPath[i] = 0;
153 i++;
154 }
155 zExe = mprintf("");
156 while( g.urlPath[i]!=0 ){
157 char *zName, *zValue;
158 zName = &g.urlPath[i];
159 zValue = zName;
160 while( g.urlPath[i] && g.urlPath[i]!='=' ){ i++; }
161 if( g.urlPath[i]=='=' ){
162 g.urlPath[i] = 0;
163 i++;
164 zValue = &g.urlPath[i];
165 while( g.urlPath[i] && g.urlPath[i]!='&' ){ i++; }
166 }
167 if( g.urlPath[i] ){
168 g.urlPath[i] = 0;
169 i++;
170 }
171 if( fossil_strcmp(zName,"fossil")==0 ){
172 g.urlFossil = zValue;
173 dehttpize(g.urlFossil);
174 zExe = mprintf("%cfossil=%T", cQuerySep, g.urlFossil);
175 cQuerySep = '&';
176 }
177 }
178
179 dehttpize(g.urlPath);
180 if( g.urlDfltPort==g.urlPort ){
181 g.urlCanonical = mprintf(
182 "%s://%s%T%T%s",
183 g.urlProtocol, zLogin, g.urlName, g.urlPath, zExe
184 );
185 }else{
186 g.urlCanonical = mprintf(
187 "%s://%s%T:%d%T%s",
188 g.urlProtocol, zLogin, g.urlName, g.urlPort, g.urlPath, zExe
189 );
190 }
191 if( g.urlIsSsh && g.urlPath[1] ) g.urlPath++;
192 free(zLogin);
193 }else if( strncmp(zUrl, "file:", 5)==0 ){
194 g.urlIsFile = 1;
195 if( zUrl[5]=='/' && zUrl[6]=='/' ){
196 i = 7;
197 }else{
198 i = 5;
199 }
200 zFile = mprintf("%s", &zUrl[i]);
201 }else if( file_isfile(zUrl) ){
202 g.urlIsFile = 1;
203 zFile = mprintf("%s", zUrl);
204 }else if( file_isdir(zUrl)==1 ){
205 zFile = mprintf("%s/FOSSIL", zUrl);
206 if( file_isfile(zFile) ){
207 g.urlIsFile = 1;
208 }else{
209 free(zFile);
210 fossil_fatal("unknown repository: %s", zUrl);
211 }
212 }else{
213 fossil_fatal("unknown repository: %s", zUrl);
214 }
215 g.urlFlags = urlFlags;
216 if( g.urlIsFile ){
217 Blob cfile;
218 dehttpize(zFile);
219 file_canonical_name(zFile, &cfile, 0);
220 free(zFile);
221 g.urlProtocol = "file";
222 g.urlPath = "";
223 g.urlName = mprintf("%b", &cfile);
224 g.urlCanonical = mprintf("file://%T", g.urlName);
225 blob_reset(&cfile);
226 }else if( g.urlUser!=0 && g.urlPasswd==0 && (urlFlags & URL_PROMPT_PW) ){
227 url_prompt_for_password();
228 bPrompted = 1;
229 }
230 if( urlFlags & URL_REMEMBER ){
231 if( bSetUrl ){
232 db_set("last-sync-url", g.urlCanonical, 0);
233 }
234 if( !bPrompted && g.urlPasswd && g.urlUser ){
235 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
236 }
237 }
238 }
239
240 /*
241 ** COMMAND: test-urlparser
242 **
@@ -428,36 +484,48 @@
428 }
429 return blob_str(&p->url);
430 }
431
432 /*
433 ** Prompt the user for the password for g.urlUser. Store the result
434 ** in g.urlPasswd.
 
435 */
436 void url_prompt_for_password(void){
437 if( g.urlIsSsh || g.urlIsFile ) return;
438 if( isatty(fileno(stdin))
439 && (g.urlFlags & URL_PROMPT_PW)!=0
440 && (g.urlFlags & URL_PROMPTED)==0
441 ){
442 g.urlFlags |= URL_PROMPTED;
443 g.urlPasswd = prompt_for_user_password(g.urlUser);
444 if( g.urlPasswd[0]
445 && (g.urlFlags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
446 ){
447 if( save_password_prompt() ){
448 g.urlFlags |= URL_REMEMBER_PW;
449 if( g.urlFlags & URL_REMEMBER ){
450 db_set("last-sync-pw", obscure(g.urlPasswd), 0);
451 }
452 }
453 }
454 }else{
455 fossil_fatal("missing or incorrect password for user \"%s\"",
456 g.urlUser);
457 }
458 }
 
 
 
 
 
 
 
 
 
 
 
459
460 /*
461 ** Remember the URL if requested.
462 */
463 void url_remember(void){
464
--- src/url.c
+++ src/url.c
@@ -28,10 +28,34 @@
28 #define URL_REMEMBER 0x002 /* Remember the url for later reuse */
29 #define URL_ASK_REMEMBER_PW 0x004 /* Ask whether to remember prompted pw */
30 #define URL_REMEMBER_PW 0x008 /* Should remember pw */
31 #define URL_PROMPTED 0x010 /* Prompted for PW already */
32
33 /*
34 ** The URL related data used with this subsystem.
35 */
36 struct UrlData {
37 /*
38 ** NOTE: These members MUST be kept in sync with the related ones in the
39 ** "Global" structure defined in "main.c".
40 */
41 int isFile; /* True if a "file:" url */
42 int isHttps; /* True if a "https:" url */
43 int isSsh; /* True if an "ssh:" url */
44 char *name; /* Hostname for http: or filename for file: */
45 char *hostname; /* The HOST: parameter on http headers */
46 char *protocol; /* "http" or "https" */
47 int port; /* TCP port number for http: or https: */
48 int dfltPort; /* The default port for the given protocol */
49 char *path; /* Pathname for http: */
50 char *user; /* User id for http: */
51 char *passwd; /* Password for http: */
52 char *canonical; /* Canonical representation of the URL */
53 char *proxyAuth; /* Proxy-Authorizer: string */
54 char *fossil; /* The fossil query parameter on ssh: */
55 unsigned flags; /* Boolean flags controlling URL processing */
56 };
57 #endif /* INTERFACE */
58
59
60 /*
61 ** Convert a string to lower-case.
@@ -40,10 +64,203 @@
64 while( *z ){
65 *z = fossil_tolower(*z);
66 z++;
67 }
68 }
69
70 /*
71 ** Parse the given URL. Populate members of the provided UrlData structure
72 ** as follows:
73 **
74 ** isFile True if FILE:
75 ** isHttps True if HTTPS:
76 ** isSsh True if SSH:
77 ** protocol "http" or "https" or "file"
78 ** name Hostname for HTTP:, HTTPS:, SSH:. Filename for FILE:
79 ** port TCP port number for HTTP or HTTPS.
80 ** dfltPort Default TCP port number (80 or 443).
81 ** path Path name for HTTP or HTTPS.
82 ** user Userid.
83 ** passwd Password.
84 ** hostname HOST:PORT or just HOST if port is the default.
85 ** canonical The URL in canonical form, omitting the password
86 **
87 */
88 void url_parse_local(
89 const char *zUrl,
90 unsigned int urlFlags,
91 UrlData *pUrlData
92 ){
93 int i, j, c;
94 char *zFile = 0;
95 int bPrompted = 0;
96 int bSetUrl = 1;
97
98 memset(pUrlData, 0, sizeof(UrlData));
99
100 if( zUrl==0 ){
101 zUrl = db_get("last-sync-url", 0);
102 if( zUrl==0 ) return;
103 pUrlData->passwd = unobscure(db_get("last-sync-pw", 0));
104 bSetUrl = 0;
105 }
106
107 if( strncmp(zUrl, "http://", 7)==0
108 || strncmp(zUrl, "https://", 8)==0
109 || strncmp(zUrl, "ssh://", 6)==0
110 ){
111 int iStart;
112 char *zLogin;
113 char *zExe;
114 char cQuerySep = '?';
115
116 pUrlData->isFile = 0;
117 if( zUrl[4]=='s' ){
118 pUrlData->isHttps = 1;
119 pUrlData->protocol = "https";
120 pUrlData->dfltPort = 443;
121 iStart = 8;
122 }else if( zUrl[0]=='s' ){
123 pUrlData->isSsh = 1;
124 pUrlData->protocol = "ssh";
125 pUrlData->dfltPort = 22;
126 pUrlData->fossil = "fossil";
127 iStart = 6;
128 }else{
129 pUrlData->isHttps = 0;
130 pUrlData->protocol = "http";
131 pUrlData->dfltPort = 80;
132 iStart = 7;
133 }
134 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!='@'; i++){}
135 if( c=='@' ){
136 /* Parse up the user-id and password */
137 for(j=iStart; j<i && zUrl[j]!=':'; j++){}
138 pUrlData->user = mprintf("%.*s", j-iStart, &zUrl[iStart]);
139 dehttpize(pUrlData->user);
140 if( j<i ){
141 pUrlData->passwd = mprintf("%.*s", i-j-1, &zUrl[j+1]);
142 dehttpize(pUrlData->passwd);
143 }
144 if( pUrlData->isSsh && pUrlData->passwd ){
145 zLogin = mprintf("%t:*@", pUrlData->user);
146 }else{
147 zLogin = mprintf("%t@", pUrlData->user);
148 }
149 for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){}
150 pUrlData->name = mprintf("%.*s", j-i-1, &zUrl[i+1]);
151 i = j;
152 }else{
153 for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){}
154 pUrlData->name = mprintf("%.*s", i-iStart, &zUrl[iStart]);
155 zLogin = mprintf("");
156 }
157 url_tolower(pUrlData->name);
158 if( c==':' ){
159 pUrlData->port = 0;
160 i++;
161 while( (c = zUrl[i])!=0 && fossil_isdigit(c) ){
162 pUrlData->port = pUrlData->port*10 + c - '0';
163 i++;
164 }
165 pUrlData->hostname = mprintf("%s:%d", pUrlData->name, pUrlData->port);
166 }else{
167 pUrlData->port = pUrlData->dfltPort;
168 pUrlData->hostname = pUrlData->name;
169 }
170 dehttpize(pUrlData->name);
171 pUrlData->path = mprintf("%s", &zUrl[i]);
172 for(i=0; pUrlData->path[i] && pUrlData->path[i]!='?'; i++){}
173 if( pUrlData->path[i] ){
174 pUrlData->path[i] = 0;
175 i++;
176 }
177 zExe = mprintf("");
178 while( pUrlData->path[i]!=0 ){
179 char *zName, *zValue;
180 zName = &pUrlData->path[i];
181 zValue = zName;
182 while( pUrlData->path[i] && pUrlData->path[i]!='=' ){ i++; }
183 if( pUrlData->path[i]=='=' ){
184 pUrlData->path[i] = 0;
185 i++;
186 zValue = &pUrlData->path[i];
187 while( pUrlData->path[i] && pUrlData->path[i]!='&' ){ i++; }
188 }
189 if( pUrlData->path[i] ){
190 pUrlData->path[i] = 0;
191 i++;
192 }
193 if( fossil_strcmp(zName,"fossil")==0 ){
194 pUrlData->fossil = zValue;
195 dehttpize(pUrlData->fossil);
196 zExe = mprintf("%cfossil=%T", cQuerySep, pUrlData->fossil);
197 cQuerySep = '&';
198 }
199 }
200
201 dehttpize(pUrlData->path);
202 if( pUrlData->dfltPort==pUrlData->port ){
203 pUrlData->canonical = mprintf(
204 "%s://%s%T%T%s",
205 pUrlData->protocol, zLogin, pUrlData->name, pUrlData->path, zExe
206 );
207 }else{
208 pUrlData->canonical = mprintf(
209 "%s://%s%T:%d%T%s",
210 pUrlData->protocol, zLogin, pUrlData->name, pUrlData->port,
211 pUrlData->path, zExe
212 );
213 }
214 if( pUrlData->isSsh && pUrlData->path[1] ) pUrlData->path++;
215 free(zLogin);
216 }else if( strncmp(zUrl, "file:", 5)==0 ){
217 pUrlData->isFile = 1;
218 if( zUrl[5]=='/' && zUrl[6]=='/' ){
219 i = 7;
220 }else{
221 i = 5;
222 }
223 zFile = mprintf("%s", &zUrl[i]);
224 }else if( file_isfile(zUrl) ){
225 pUrlData->isFile = 1;
226 zFile = mprintf("%s", zUrl);
227 }else if( file_isdir(zUrl)==1 ){
228 zFile = mprintf("%s/FOSSIL", zUrl);
229 if( file_isfile(zFile) ){
230 pUrlData->isFile = 1;
231 }else{
232 free(zFile);
233 fossil_fatal("unknown repository: %s", zUrl);
234 }
235 }else{
236 fossil_fatal("unknown repository: %s", zUrl);
237 }
238 pUrlData->flags = urlFlags;
239 if( pUrlData->isFile ){
240 Blob cfile;
241 dehttpize(zFile);
242 file_canonical_name(zFile, &cfile, 0);
243 free(zFile);
244 pUrlData->protocol = "file";
245 pUrlData->path = "";
246 pUrlData->name = mprintf("%b", &cfile);
247 pUrlData->canonical = mprintf("file://%T", pUrlData->name);
248 blob_reset(&cfile);
249 }else if( pUrlData->user!=0 && pUrlData->passwd==0 && (urlFlags & URL_PROMPT_PW) ){
250 url_prompt_for_password();
251 bPrompted = 1;
252 }
253 if( urlFlags & URL_REMEMBER ){
254 if( bSetUrl ){
255 db_set("last-sync-url", pUrlData->canonical, 0);
256 }
257 if( !bPrompted && pUrlData->passwd && pUrlData->user ){
258 db_set("last-sync-pw", obscure(pUrlData->passwd), 0);
259 }
260 }
261 }
262
263 /*
264 ** Parse the given URL, which describes a sync server. Populate variables
265 ** in the global "g" structure as follows:
266 **
@@ -68,175 +285,14 @@
285 **
286 ** ssh://userid:password@host:port/path?fossil=path/to/fossil.exe
287 **
288 */
289 void url_parse(const char *zUrl, unsigned int urlFlags){
290 UrlData urlData;
291 memcpy(&urlData, GLOBAL_URL(), sizeof(UrlData));
292 url_parse_local(zUrl, urlFlags, &urlData);
293 memcpy(GLOBAL_URL(), &urlData, sizeof(UrlData));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294 }
295
296 /*
297 ** COMMAND: test-urlparser
298 **
@@ -428,36 +484,48 @@
484 }
485 return blob_str(&p->url);
486 }
487
488 /*
489 ** Prompt the user for the password that corresponds to the "user" member of
490 ** the provided UrlData structure. Store the result into the "passwd" member
491 ** of the provided UrlData structure.
492 */
493 void url_prompt_for_password_local(UrlData *pUrlData){
494 if( pUrlData->isSsh || pUrlData->isFile ) return;
495 if( isatty(fileno(stdin))
496 && (pUrlData->flags & URL_PROMPT_PW)!=0
497 && (pUrlData->flags & URL_PROMPTED)==0
498 ){
499 pUrlData->flags |= URL_PROMPTED;
500 pUrlData->passwd = prompt_for_user_password(pUrlData->user);
501 if( pUrlData->passwd[0]
502 && (pUrlData->flags & (URL_REMEMBER|URL_ASK_REMEMBER_PW))!=0
503 ){
504 if( save_password_prompt() ){
505 pUrlData->flags |= URL_REMEMBER_PW;
506 if( pUrlData->flags & URL_REMEMBER ){
507 db_set("last-sync-pw", obscure(pUrlData->passwd), 0);
508 }
509 }
510 }
511 }else{
512 fossil_fatal("missing or incorrect password for user \"%s\"",
513 pUrlData->user);
514 }
515 }
516
517 /*
518 ** Prompt the user for the password for g.urlUser. Store the result
519 ** in g.urlPasswd.
520 */
521 void url_prompt_for_password(void){
522 UrlData urlData;
523 memcpy(&urlData, GLOBAL_URL(), sizeof(UrlData));
524 url_prompt_for_password_local(&urlData);
525 memcpy(GLOBAL_URL(), &urlData, sizeof(UrlData));
526 }
527
528 /*
529 ** Remember the URL if requested.
530 */
531 void url_remember(void){
532
+2 -2
--- src/xfer.c
+++ src/xfer.c
@@ -1892,12 +1892,12 @@
18921892
18931893
fossil_force_newline();
18941894
fossil_print(
18951895
"%s finished with %lld bytes sent, %lld bytes received\n",
18961896
zOpType, nSent, nRcvd);
1897
- transport_close();
1898
- transport_global_shutdown();
1897
+ transport_close(GLOBAL_URL());
1898
+ transport_global_shutdown(GLOBAL_URL());
18991899
db_multi_exec("DROP TABLE onremote");
19001900
manifest_crosslink_end();
19011901
content_enable_dephantomize(1);
19021902
db_end_transaction(0);
19031903
return nErr;
19041904
--- src/xfer.c
+++ src/xfer.c
@@ -1892,12 +1892,12 @@
1892
1893 fossil_force_newline();
1894 fossil_print(
1895 "%s finished with %lld bytes sent, %lld bytes received\n",
1896 zOpType, nSent, nRcvd);
1897 transport_close();
1898 transport_global_shutdown();
1899 db_multi_exec("DROP TABLE onremote");
1900 manifest_crosslink_end();
1901 content_enable_dephantomize(1);
1902 db_end_transaction(0);
1903 return nErr;
1904
--- src/xfer.c
+++ src/xfer.c
@@ -1892,12 +1892,12 @@
1892
1893 fossil_force_newline();
1894 fossil_print(
1895 "%s finished with %lld bytes sent, %lld bytes received\n",
1896 zOpType, nSent, nRcvd);
1897 transport_close(GLOBAL_URL());
1898 transport_global_shutdown(GLOBAL_URL());
1899 db_multi_exec("DROP TABLE onremote");
1900 manifest_crosslink_end();
1901 content_enable_dephantomize(1);
1902 db_end_transaction(0);
1903 return nErr;
1904

Keyboard Shortcuts

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