@@ -173,14 +173,35 @@
}
#endif
/*
+** zLine is a line from the header of an HTTP reply. Find the
+** "argument" to this header line. The argument is the first non-whitespace
+** character following the first ":" in the line. The argument consists of
+** non-whitespace and non-semicolon characters. Zero-terminate the argument
+** before returning.
+*/
+static char *header_arg(char *zIn){
+ char *z;
+ while( *zIn && *zIn!=':' ){ zIn++; }
+ if( *zIn==':' ){ zIn++; }
+ while( isspace(*zIn) ){ zIn++; }
+ for(z=zIn; *z && *z!=';' && !isspace(*z); z++){}
+ *z = 0;
+ return zIn;
+}
+
+/*
** Make a single attempt to talk to the server. Return TRUE on success
** and FALSE on a failure.
**
** pHeader contains the HTTP header. pPayload contains the content.
** The content of the reply is written into pReply. pReply is assumed
** to be uninitialized prior to this call.
+**
+** pPayload has already been compressed and/or encrypted prior to being
+** passed into this function. pReply will be decrypted and/or decompressed
+** as required by this function, based on the Content-Type of the reply.
**
** If an error occurs, this routine return false, resets pReply and
** closes the persistent connection, if any.
*/
@@ -190,8 +211,10 @@
int iLength;
int iHttpVersion;
int i;
int nRead;
+ int needDecrypt = 0;
+ int needDecompress = 0;
char zLine[2000];
if( pSocket==0 && http_open_socket() ){
return 0;
@@ -220,16 +243,25 @@
closeConnection = 1;
}else{
closeConnection = 0;
}
- } else if( strncasecmp(zLine, "content-length:", 15)==0 ){
- iLength = atoi(&zLine[16]);
+ }else if( strncasecmp(zLine,"content-length:",15)==0 ){
+ iLength = atoi(header_arg(zLine));
}else if( strncasecmp(zLine, "connection:", 11)==0 ){
- for(i=12; isspace(zLine[i]); i++){}
- if( zLine[i]=='c' || zLine[i]=='C' ){
- closeConnection = 1;
- }else if( zLine[i]=='k' || zLine[i]=='K' ){
- closeConnection = 0;
+ int c = header_arg(zLine)[0];
+ if( c=='c' || c=='C' ){
+ closeConnection = 1; /* Connection: close */
+ }else if( c=='k' || c=='K' ){
+ closeConnection = 0; /* Connection: keep-alive */
+ }
+ }else if( strncasecmp(zLine, "content-type:", 13)==0 ){
+ const char *zType = header_arg(zLine);
+ if( strcmp(zType, "application/x-fossil")==0 ){
+ needDecompress = 1;
+ needDecrypt = 0;
+ }else if( strcmp(zType, "application/x-fossil-secure")==0 ){
+ needDecompress = 1;
+ needDecrypt = 1;
}
}
}
if( iLength<0 ) goto write_err;
@@ -252,15 +284,24 @@
for(i=0; zLine[i] && zLine[i]!='\n' && zLine[i]!='\r'; i++){}
if( i==0 ) break;
zLine[i] = 0;
if( strncasecmp(zLine,"content-length:",15)==0 ){
- iLength = atoi(&zLine[16]);
+ iLength = atoi(header_arg(zLine));
}else if( strncasecmp(zLine, "connection:", 11)==0 ){
- for(i=12; isspace(zLine[i]); i++){}
- if( zLine[i]=='c' || zLine[i]=='C' ){
+ int c = header_arg(zLine)[0];
+ if( c=='c' || c=='C' ){
closeConnection = 1; /* Connection: close */
- }else if( zLine[i]=='k' || zLine[i]=='K' ){
+ }else if( c=='k' || c=='K' ){
closeConnection = 0; /* Connection: keep-alive */
+ }
+ }else if( strncasecmp(zLine, "content-type:", 13)==0 ){
+ const char *zType = header_arg(zLine);
+ if( strcmp(zType, "application/x-fossil")==0 ){
+ needDecompress = 1;
+ needDecrypt = 0;
+ }else if( strcmp(zType, "application/x-fossil-secure")==0 ){
+ needDecompress = 1;
+ needDecrypt = 1;
}
}
}
if( iLength<0 ) goto write_err;
@@ -271,8 +312,14 @@
goto write_err;
}
if( closeConnection ){
http_close();
+ }
+ if( needDecrypt ){
+ blob_decrypt(pReply, g.urlPasswd, pReply);
+ }
+ if( needDecompress ){
+ blob_uncompress(pReply, pReply);
}
return 1;
write_err:
@@ -342,9 +389,13 @@
blob_reset(&sig);
/* Construct the payload, which includes the login card.
*/
- if( g.fHttpTrace ){
+ if( g.fHttpSecure && g.urlPasswd[0] ){
+ blob_compress(pSend, pSend);
+ payload = login;
+ blob_encrypt(pSend, g.urlPasswd, &payload);
+ }else if( g.fHttpTrace ){
payload = login;
blob_append(&payload, blob_buffer(pSend), blob_size(pSend));
}else{
blob_compress2(&login, pSend, &payload);
@@ -362,9 +413,11 @@
}
blob_appendf(&hdr, "POST %s%sxfer HTTP/1.1\r\n", g.urlPath, zSep);
blob_appendf(&hdr, "Host: %s\r\n", g.urlHostname);
blob_appendf(&hdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n");
- if( g.fHttpTrace ){
+ if( g.fHttpSecure && g.urlPasswd[0] ){
+ blob_appendf(&hdr, "Content-Type: application/x-fossil-secure\r\n");
+ }else if( g.fHttpTrace ){
blob_appendf(&hdr, "Content-Type: application/x-fossil-debug\r\n");
}else{
blob_appendf(&hdr, "Content-Type: application/x-fossil\r\n");
}
@@ -404,14 +457,13 @@
blob_reset(&hdr);
blob_reset(&payload);
/* Process the reply. pRecv contains only the payload of the
- ** reply message, not the header.
+ ** reply message, not the header. pRecv has already been decrypted
+ ** and decompressed
*/
if( g.fHttpTrace ){
printf("HTTP RECEIVE:\n%s\n=======================\n", blob_str(pRecv));
- }else{
- blob_uncompress(pRecv, pRecv);
}
}