Check-in [16f6fd904a]
Not logged in
Overview

SHA1 Hash:16f6fd904a0c88f7e1312704ee84675899181ee1
Date: 2009-11-09 15:32:32
User: dmitry
Comment:Add SSL support.
Timelines: ancestors | descendants | both | ssl
Other Links: files | ZIP archive | manifest

Tags And Properties
Changes
[hide diffs]

Modified Makefile from [c357142045] to [c4d30a7b4e].

@@ -16,19 +16,28 @@
 #### The suffix to add to executable files.  ".exe" for windows.
 #    Nothing for unix.
 #
 E =
 
+#### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
+#
+# FOSSIL_ENABLE_SSL=1
+
 #### C Compile and options for use in building executables that
 #    will run on the target platform.  This is usually the same
 #    as BCC, unless you are cross-compiling.  This C compiler builds
 #    the finished binary for fossil.  The BCC compiler above is used
 #    for building intermediate code-generator tools.
 #
 #TCC = gcc -O6
 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
 TCC = gcc -g -Os -Wall
+
+# With HTTPS support
+ifdef FOSSIL_ENABLE_SSL
+TCC += -DFOSSIL_ENABLE_SSL=1
+endif
 
 #### Extra arguments for linking the finished binary.  Fossil needs
 #    to link against the Z-Lib compression library.  There are no
 #    other dependencies.  We sometimes add the -static option here
 #    so that we can build a static executable that will run in a
@@ -38,14 +47,18 @@
 # If you're on OpenSolaris:
 # LIB += lsocket
 # Solaris 10 needs:
 # LIB += -lsocket -lnsl
 # My assumption is that the Sol10 flags will work for Sol8/9 and possibly 11.
-
+#
+# OpenSSL:
+ifdef FOSSIL_ENABLE_SSL
+LIB += -lcrypto -lssl
+endif
 
 #### Tcl shell for use in running the fossil testsuite.
 #
 TCLSH = tclsh
 
 # You should not need to change anything below this line
 ###############################################################################
 include $(SRCDIR)/main.mk

Modified Makefile.w32 from [900e354562] to [c389f88ac5].

@@ -16,10 +16,14 @@
 #### The suffix to add to executable files.  ".exe" for windows.
 #    Nothing for unix.
 #
 E = .exe
 
+#### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
+#
+# FOSSIL_ENABLE_SSL=1
+
 #### C Compile and options for use in building executables that
 #    will run on the target platform.  This is usually the same
 #    as BCC, unless you are cross-compiling.  This C compiler builds
 #    the finished binary for fossil.  The BCC compiler above is used
 #    for building intermediate code-generator tools.
@@ -28,22 +32,31 @@
 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
 #TCC = gcc -g -Os -Wall
 #TCC = gcc -g -Os -Wall -DFOSSIL_I18N=0 -L/usr/local/lib -I/usr/local/include
 TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L/mingw/lib -I/mingw/include
 
+# With HTTPS support
+ifdef FOSSIL_ENABLE_SSL
+TCC += -DFOSSIL_ENABLE_SSL=1
+endif
+
 #### Extra arguments for linking the finished binary.  Fossil needs
 #    to link against the Z-Lib compression library.  There are no
 #    other dependencies.  We sometimes add the -static option here
 #    so that we can build a static executable that will run in a
 #    chroot jail.
 #
 #LIB = -lz
 #LIB = -lz -lws2_32
 LIB = -lmingwex -lz -lws2_32
+# OpenSSL:
+ifdef FOSSIL_ENABLE_SSL
+LIB += -lcrypto -lssl
+endif
 
 #### Tcl shell for use in running the fossil testsuite.
 #
 TCLSH = tclsh
 
 # You should not need to change anything below this line
 ###############################################################################
 include $(SRCDIR)/main.mk

Added src/http_ssl.c version [77d02aa7e4]

@@ -1,1 +1,292 @@
+/*
+** Copyright (c) 2009 D. Richard Hipp
+**
+** This program is free software; you can redistribute it and/or
+** modify it under the terms of the GNU General Public
+** License version 2 as published by the Free Software Foundation.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+** General Public License for more details.
+**
+** You should have received a copy of the GNU General Public
+** License along with this library; if not, write to the
+** Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+** Boston, MA  02111-1307, USA.
+**
+** Author contact information:
+**   drh@hwaci.com
+**   http://www.hwaci.com/drh/
+**
+*******************************************************************************
+**
+** This file manages low-level SSL communications.
+**
+** This file implements a singleton.  A single SSL connection may be active
+** at a time.  State information is stored in static variables.  The identity
+** of the server is held in global variables that are set by url_parse().
+**
+** SSL support is abstracted out into this module because Fossil can
+** be compiled without SSL support (which requires OpenSSL library)
+*/
+
+#include "config.h"
+
+#ifdef FOSSIL_ENABLE_SSL
+
+#include <openssl/bio.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "http_ssl.h"
+#include <assert.h>
+#include <sys/types.h>
+
+/*
+** There can only be a single OpenSSL IO connection open at a time.
+** State information about that IO is stored in the following
+** local variables:
+*/
+static int sslIsInit = 0;    /* True after global initialization */
+static BIO *iBio;            /* OpenSSL I/O abstraction */
+static char *sslErrMsg = 0;  /* Text of most recent OpenSSL error */
+static SSL_CTX *sslCtx;      /* SSL context */
+static SSL *ssl;
+
+
+/*
+** Clear the SSL error message
+*/
+static void ssl_clear_errmsg(void){
+  free(sslErrMsg);
+  sslErrMsg = 0;
+}
+
+/*
+** Set the SSL error message.
+*/
+void ssl_set_errmsg(char *zFormat, ...){
+  va_list ap;
+  ssl_clear_errmsg();
+  va_start(ap, zFormat);
+  sslErrMsg = vmprintf(zFormat, ap);
+  va_end(ap);
+}
+
+/*
+** Return the current SSL error message
+*/
+const char *ssl_errmsg(void){
+  return sslErrMsg;
+}
+
+/*
+** Call this routine once before any other use of the SSL interface.
+** This routine does initial configuration of the SSL module.
+*/
+void ssl_global_init(void){
+  if( sslIsInit==0 ){
+    SSL_library_init();
+    SSL_load_error_strings();
+    ERR_load_BIO_strings();
+    OpenSSL_add_all_algorithms();
+    sslCtx = SSL_CTX_new(SSLv23_client_method());
+    sslIsInit = 1;
+  }
+}
+
+/*
+** Call this routine to shutdown the SSL module prior to program exit.
+*/
+void ssl_global_shutdown(void){
+  if( sslIsInit ){
+    SSL_CTX_free(sslCtx);
+    ssl_clear_errmsg();
+    sslIsInit = 0;
+  }
+}
+
+/*
+** Close the currently open SSL connection.  If no connection is open,
+** this routine is a no-op.
+*/
+void ssl_close(void){
+  if( iBio!=NULL ){
+    BIO_reset(iBio);
+    BIO_free_all(iBio);
+  }
+}
+
+/*
+** Open an SSL connection.  The identify of the server is determined
+** by global varibles that are set using url_parse():
+**
+**    g.urlName       Name of the server.  Ex: www.fossil-scm.org
+**    g.urlPort       TCP/IP port to use.  Ex: 80
+**
+** Return the number of errors.
+*/
+int ssl_open(void){
+  X509 *cert;
+  int hasSavedCertificate = 0;
+
+  ssl_global_init();
+
+  /* Get certificate for current server from global config and
+   * (if we have it in config) add it to certificate store.
+   */
+  cert = ssl_get_certificate();
+  if ( cert != NULL ){
+    X509_STORE_add_cert(SSL_CTX_get_cert_store(sslCtx), cert);
+    X509_free(cert);
+    hasSavedCertificate = 1;
+  }
+
+  iBio = BIO_new_ssl_connect(sslCtx);
+  BIO_get_ssl(iBio, &ssl);
+  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+  if( iBio==NULL ) {
+    ssl_set_errmsg("SSL: cannot open SSL (%s)",
+                    ERR_reason_error_string(ERR_get_error()));
+    return 1;
+  }
+
+  char *connStr = mprintf("%s:%d", g.urlName, g.urlPort);
+  BIO_set_conn_hostname(iBio, connStr);
+  free(connStr);
+
+  if( BIO_do_connect(iBio)<=0 ){
+    ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
+        g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
+    ssl_close();
+    return 1;
+  }
+
+  if( BIO_do_handshake(iBio)<=0 ) {
+    ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
+        g.urlName, g.urlPort, ERR_reason_error_string(ERR_get_error()));
+    ssl_close();
+    return 1;
+  }
+  /* Check if certificate is valid */
+  cert = SSL_get_peer_certificate(ssl);
+
+  if ( cert == NULL ){
+    ssl_set_errmsg("No SSL certificate was presented by the peer");
+    ssl_close();
+    return 1;
+  }
+
+  if( SSL_get_verify_result(ssl) != X509_V_OK ){
+    char *desc, *prompt;
+    BIO *mem;
+
+    mem = BIO_new(BIO_s_mem());
+    X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE);
+    BIO_puts(mem, "\n\nIssued By:\n\n");
+    X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE);
+    BIO_write(mem, "", 1); // null-terminate mem buffer
+    BIO_get_mem_data(mem, &desc);
+
+    char *warning = "";
+    if( hasSavedCertificate ){
+      warning = "WARNING: Certificate doesn't match the "
+                "saved certificate for this host!";
+    }
+    prompt = mprintf("\nUnknown SSL certificate:\n\n%s\n\n%s\n"
+                     "Accept certificate [a=always/y/N]? ", desc, warning);
+    BIO_free(mem);
+
+    Blob ans;
+    blob_zero(&ans);
+    prompt_user(prompt, &ans);
+    free( prompt );
+    if( blob_str(&ans)[0]!='y' && blob_str(&ans)[0]!='a' ) {
+      X509_free(cert);
+      ssl_set_errmsg("SSL certificate declined");
+      ssl_close();
+      return 1;
+    }
+    if( blob_str(&ans)[0]=='a' ) {
+      ssl_save_certificate(cert);
+    }
+  }
+  X509_free(cert);
+  return 0;
+}
+
+/*
+** Save certificate to global config.
+*/
+void ssl_save_certificate(X509 *cert)
+{
+  BIO *mem;
+  char *zCert, *zHost;
+
+  mem = BIO_new(BIO_s_mem());
+  PEM_write_bio_X509(mem, cert);
+  BIO_write(mem, "", 1); // null-terminate mem buffer
+  BIO_get_mem_data(mem, &zCert);
+  zHost = mprintf("cert:%s", g.urlName);
+  db_set(zHost, zCert, 1);
+  free(zHost);
+  BIO_free(mem);
+}
+
+/*
+** Get certificate for g.urlName from global config.
+** Return NULL if no certificate found.
+*/
+X509 *ssl_get_certificate()
+{
+  char *zHost, *zCert;
+  BIO *mem;
+  X509 *cert;
+
+  zHost = mprintf("cert:%s", g.urlName);
+  zCert = db_get(zHost, NULL);
+  free(zHost);
+  if ( zCert==NULL )
+    return NULL;
+  mem = BIO_new(BIO_s_mem());
+  BIO_puts(mem, zCert);
+  cert = PEM_read_bio_X509(mem, NULL, 0, NULL);
+  free(zCert);
+  BIO_free(mem);
+  return cert;
+}
+
+/*
+** Send content out over the SSL connection.
+*/
+size_t ssl_send(void *NotUsed, void *pContent, size_t N){
+  size_t sent;
+  size_t total = 0;
+  while( N>0 ){
+    sent = BIO_write(iBio, pContent, N);
+    if( sent<=0 ) break;
+    total += sent;
+    N -= sent;
+    pContent = (void*)&((char*)pContent)[sent];
+  }
+  return total;
+}
+
+/*
+** Receive content back from the SSL connection.
+*/
+size_t ssl_receive(void *NotUsed, void *pContent, size_t N){
+  size_t got;
+  size_t total = 0;
+  while( N>0 ){
+    got = BIO_read(iBio, pContent, N);
+    if( got<=0 ) break;
+    total += got;
+    N -= got;
+    pContent = (void*)&((char*)pContent)[got];
+  }
+  return total;
+}
 
+#endif /* FOSSIL_ENABLE_SSL */

Modified src/http_transport.c from [a410394220] to [bc7f5938ff].

@@ -49,10 +49,15 @@
 
 /*
 ** Return the current transport error message.
 */
 const char *transport_errmsg(void){
+  #ifdef FOSSIL_ENABLE_SSL
+  if( g.urlIsHttps ){
+    return ssl_errmsg();
+  }
+  #endif
   return socket_errmsg();
 }
 
 /*
 ** Retrieve send/receive counts from the transport layer.  If "resetFlag"
@@ -79,12 +84,17 @@
 */
 int transport_open(void){
   int rc = 0;
   if( transport.isOpen==0 ){
     if( g.urlIsHttps ){
-      socket_set_errmsg("HTTPS: is not yet implemented");
+      #ifdef FOSSIL_ENABLE_SSL
+      rc = ssl_open();
+      if( rc==0 ) transport.isOpen = 1;
+      #else
+      socket_set_errmsg("HTTPS: Fossil has been compiled without SSL support");
       rc = 1;
+      #endif
     }else if( g.urlIsFile ){
       sqlite3_uint64 iRandId;
       sqlite3_randomness(sizeof(iRandId), &iRandId);
       transport.zOutFile = mprintf("%s-%llu-out.http",
                                        g.zRepositoryName, iRandId);
@@ -112,11 +122,13 @@
     transport.pBuf = 0;
     transport.nAlloc = 0;
     transport.nUsed = 0;
     transport.iCursor = 0;
     if( g.urlIsHttps ){
-      /* TBD */
+      #ifdef FOSSIL_ENABLE_SSL
+      ssl_close();
+      #endif
     }else if( g.urlIsFile ){
       if( transport.pFile ){
         fclose(transport.pFile);
         transport.pFile = 0;
       }
@@ -137,11 +149,19 @@
 void transport_send(Blob *toSend){
   char *z = blob_buffer(toSend);
   int n = blob_size(toSend);
   transport.nSent += n;
   if( g.urlIsHttps ){
-    /* TBD */
+    #ifdef FOSSIL_ENABLE_SSL
+    int sent;
+    while( n>0 ){
+      sent = ssl_send(0, z, n);
+      /* printf("Sent %d of %d bytes\n", sent, n); fflush(stdout); */
+      if( sent<=0 ) break;
+      n -= sent;
+    }
+    #endif
   }else if( g.urlIsFile ){
     fwrite(z, 1, n, transport.pFile);
   }else{
     int sent;
     while( n>0 ){
@@ -204,12 +224,16 @@
     nByte += toMove;
   }
   if( N>0 ){
     int got;
     if( g.urlIsHttps ){
-      /* TBD */
+      #ifdef FOSSIL_ENABLE_SSL
+      got = ssl_receive(0, zBuf, N);
+      /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
+      #else
       got = 0;
+      #endif
     }else if( g.urlIsFile ){
       got = fread(zBuf, 1, N, transport.pFile);
     }else{
       got = socket_receive(0, zBuf, N);
       /* printf("received %d of %d bytes\n", got, N); fflush(stdout); */
@@ -292,6 +316,16 @@
     }
     i++;
   }
   /* printf("Got line: [%s]\n", &transport.pBuf[iStart]); */
   return &transport.pBuf[iStart];
+}
+
+void *transport_global_shutdown(void){
+  if( g.urlIsHttps ){
+    #ifdef FOSSIL_ENABLE_SSL
+    ssl_global_shutdown();
+    #endif
+  }else{
+    socket_global_shutdown();
+  }
 }

Modified src/main.mk from [08be0ee0ca] to [ad6939d32a].

@@ -39,10 +39,11 @@
   $(SRCDIR)/encode.c \
   $(SRCDIR)/file.c \
   $(SRCDIR)/finfo.c \
   $(SRCDIR)/http.c \
   $(SRCDIR)/http_socket.c \
+  $(SRCDIR)/http_ssl.c \
   $(SRCDIR)/http_transport.c \
   $(SRCDIR)/info.c \
   $(SRCDIR)/login.c \
   $(SRCDIR)/main.c \
   $(SRCDIR)/manifest.c \
@@ -109,10 +110,11 @@
   encode_.c \
   file_.c \
   finfo_.c \
   http_.c \
   http_socket_.c \
+  http_ssl_.c \
   http_transport_.c \
   info_.c \
   login_.c \
   main_.c \
   manifest_.c \
@@ -179,10 +181,11 @@
   encode.o \
   file.o \
   finfo.o \
   http.o \
   http_socket.o \
+  http_ssl.o \
   http_transport.o \
   info.o \
   login.o \
   main.o \
   manifest.o \
@@ -261,16 +264,16 @@
 	# noop
 
 clean:
 	rm -f *.o *_.c $(APPNAME) VERSION.h
 	rm -f translate makeheaders mkindex page_index.h headers
-	rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h http.h http_socket.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
+	rm -f add.h allrepo.h bag.h blob.h branch.h browse.h captcha.h cgi.h checkin.h checkout.h clearsign.h clone.h comformat.h configure.h construct.h content.h db.h delta.h deltacmd.h descendants.h diff.h diffcmd.h doc.h encode.h file.h finfo.h http.h http_socket.h http_ssl.h http_transport.h info.h login.h main.h manifest.h md5.h merge.h merge3.h name.h pivot.h pqueue.h printf.h rebuild.h report.h rss.h rstats.h schema.h search.h setup.h sha1.h shun.h stat.h style.h sync.h tag.h th_main.h timeline.h tkt.h tktsetup.h undo.h update.h url.h user.h verify.h vfile.h wiki.h wikiformat.h winhttp.h xfer.h zip.h
 
 page_index.h: $(TRANS_SRC) mkindex
 	./mkindex $(TRANS_SRC) >$@
 headers:	page_index.h makeheaders VERSION.h
-	./makeheaders  add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h http_.c:http.h http_socket_.c:http_socket.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
+	./makeheaders  add_.c:add.h allrepo_.c:allrepo.h bag_.c:bag.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h construct_.c:construct.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h file_.c:file.h finfo_.c:finfo.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h info_.c:info.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h pivot_.c:pivot.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h rstats_.c:rstats.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h VERSION.h
 	touch headers
 headers: Makefile
 Makefile:
 add_.c:	$(SRCDIR)/add.c translate
 	./translate $(SRCDIR)/add.c >add_.c
@@ -466,10 +469,17 @@
 
 http_socket.o:	http_socket_.c http_socket.h  $(SRCDIR)/config.h
 	$(XTCC) -o http_socket.o -c http_socket_.c
 
 http_socket.h:	headers
+http_ssl_.c:	$(SRCDIR)/http_ssl.c translate
+	./translate $(SRCDIR)/http_ssl.c >http_ssl_.c
+
+http_ssl.o:	http_ssl_.c http_ssl.h  $(SRCDIR)/config.h
+	$(XTCC) -o http_ssl.o -c http_ssl_.c
+
+http_ssl.h:	headers
 http_transport_.c:	$(SRCDIR)/http_transport.c translate
 	./translate $(SRCDIR)/http_transport.c >http_transport_.c
 
 http_transport.o:	http_transport_.c http_transport.h  $(SRCDIR)/config.h
 	$(XTCC) -o http_transport.o -c http_transport_.c

Modified src/makemake.tcl from [8696139730] to [9cb9f06ef7].

@@ -73,10 +73,11 @@
   wiki
   wikiformat
   winhttp
   xfer
   zip
+  http_ssl
 }
 
 # Name of the final application
 #
 set name fossil

Modified src/xfer.c from [b02eb5519c] to [136cf94151].

@@ -1270,10 +1270,10 @@
   };
   transport_stats(&nSent, &nRcvd, 1);
   printf("Total network traffic: %d bytes sent, %d bytes received\n",
          nSent, nRcvd);
   transport_close();
-  socket_global_shutdown();
+  transport_global_shutdown();
   db_multi_exec("DROP TABLE onremote");
   manifest_crosslink_end();
   db_end_transaction(0);
 }