← Back to team overview

kicad-developers team mailing list archive

Patch to replace avhttp by curl in stable branch

 

Hi all,

I wrote this patch to allow users who cannot use avhttp for some reason to compile the *stable*
branch using curl instead of avhttp, when using github plugin.

I tested it on W7 and Kubuntu 14.04.

However the more tests the better.

Please test it and see if there are issues (I could have missed something among the lot of
patches related to this replacement)

Thanks.

It could be merged in stable 4.06 ( if exists...)


-- 
Jean-Pierre CHARRAS
>From e5c02a4325806c848c7b51e1d6b3af122b0b00d9 Mon Sep 17 00:00:00 2001
From: jean-pierre charras <jp.charras@xxxxxxxxxx>
Date: Wed, 7 Dec 2016 18:43:57 +0100
Subject: [PATCH] Try to replace avhttp by Curl

---
 CMakeLists.txt                         |   4 +
 CMakeModules/download_avhttp.cmake     |  65 ----------
 Documentation/development/compiling.md |  12 +-
 common/CMakeLists.txt                  |  15 ++-
 common/basicframe.cpp                  |  13 ++
 common/footprint_info.cpp              |  30 ++---
 common/kicad_curl/kicad_curl.cpp       | 224 +++++++++++++++++++++++++++++++++
 common/kicad_curl/kicad_curl_easy.cpp  |  94 ++++++++++++++
 include/kicad_curl/kicad_curl.h        | 108 ++++++++++++++++
 include/kicad_curl/kicad_curl_easy.h   | 184 +++++++++++++++++++++++++++
 pcbnew/CMakeLists.txt                  |   4 +-
 pcbnew/github/CMakeLists.txt           |  40 +-----
 pcbnew/github/github_getliblist.cpp    |  70 ++++++-----
 pcbnew/github/github_getliblist.h      |   4 +-
 pcbnew/github/github_plugin.cpp        | 180 ++++++++------------------
 pcbnew/github/github_plugin.h          |   4 +-
 16 files changed, 755 insertions(+), 296 deletions(-)
 delete mode 100644 CMakeModules/download_avhttp.cmake
 create mode 100644 common/kicad_curl/kicad_curl.cpp
 create mode 100644 common/kicad_curl/kicad_curl_easy.cpp
 create mode 100644 include/kicad_curl/kicad_curl.h
 create mode 100644 include/kicad_curl/kicad_curl_easy.h

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6eea373..09932cc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -569,6 +569,10 @@ if( NOT GLEW_FOUND )
     check_find_package_result( GLEW_FOUND "GLEW" )
 endif()
 
+# Find CURL library
+find_package( CURL REQUIRED )
+
+
 ######################
 # Find Cairo library #
 ######################
diff --git a/CMakeModules/download_avhttp.cmake b/CMakeModules/download_avhttp.cmake
deleted file mode 100644
index abc52b7..0000000
--- a/CMakeModules/download_avhttp.cmake
+++ /dev/null
@@ -1,65 +0,0 @@
-#  This program source code file is part of KICAD, a free EDA CAD application.
-#
-#  Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
-#  Copyright (C) 2013 Kicad Developers, see AUTHORS.txt for contributors.
-#
-#  This program is free software; you can redistribute it and/or
-#  modify it under the terms of the GNU General Public License
-#  as published by the Free Software Foundation; either version 2
-#  of the License, or (at your option) any later version.
-#
-#  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 program; if not, you may find one here:
-#  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
-#  or you may search the http://www.gnu.org website for the version 2 license,
-#  or you may write to the Free Software Foundation, Inc.,
-#  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
-
-
-
-# Download av_http and install into ${PREFIX}, typically in our KiCad source tree.
-# Assumes include( ExternalProject ) was done inline previous to this file
-# and that set( DOWNLOAD_DIR ... ) was set in a higher context.
-
-#-----<configure>-------------------------------------------------------------------------------------
-
-# soon cmake will have https support, switch to a true download then:
-#set( AVHTTP_RELEASE ??? )
-#set( AVHTTP_MD5 ???? ) # re-calc this on every RELEASE change
-
-#-----</configure>-----------------------------------------------------------------------------------
-
-
-# Where the library is to be installed.
-set( PREFIX ${DOWNLOAD_DIR}/avhttp )
-
-if( KICAD_SKIP_BOOST )
-    set( AVHTTP_DEPEND "" )
-else()
-    set( AVHTTP_DEPEND "boost" )
-endif()
-
-
-# Install the AVHTTP header only library ${PREFIX}
-ExternalProject_Add( avhttp
-    PREFIX          ${PREFIX}
-    DOWNLOAD_DIR    ${DOWNLOAD_DIR}     # no true download yet
-
-    # grab it from a local zip file for now, cmake caller's source dir
-    URL             ${CMAKE_CURRENT_SOURCE_DIR}/avhttp-master.zip
-    DEPENDS         ${AVHTTP_DEPEND}
-
-    CONFIGURE_COMMAND ""
-
-    BUILD_COMMAND   ""
-    INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory <SOURCE_DIR> <INSTALL_DIR>
-    )
-
-
-set( AVHTTP_INCLUDE_DIR  "${PREFIX}/include" CACHE FILEPATH "AVHTTP include directory" )
-mark_as_advanced( AVHTTP_INCLUDE_DIR )
diff --git a/Documentation/development/compiling.md b/Documentation/development/compiling.md
index 90cea95..6a5ac92 100644
--- a/Documentation/development/compiling.md
+++ b/Documentation/development/compiling.md
@@ -78,14 +78,6 @@ specific patches required to build a working Boost library.  These patches can b
 [patches folder][] in the KiCad source.  These patches are named by the platform name they should
 be applied against.
 
-## OpenSSL Secure Socket Layer Library ## {#openssl}
-
-The [OpenSSL][] library is only required when the KiCad build is configured with the Github plugin
-enabled.  See the [KiCad Build Configuration Options](#build_opts)` section for more information.
-Please note that KiCad will download and build version 1.0.1e of OpenSSL by default.  You should
-probably use the version of OpenSSL installed on your system as it will most likely be more up to
-date and contain the latest security fixes.
-
 ## GLEW OpenGL Extension Wrangler Library ## {#glew}
 
 The [OpenGL Extension Wrangler][GLEW] is an OpenGL helper library used by the KiCad graphics
@@ -299,7 +291,7 @@ the following commands:
               mingw-w64-x86_64-boost \
               mingw-w64-x86_64-cairo \
               mingw-w64-x86_64-glew \
-              mingw-w64-x86_64-openssl \
+              mingw-w64-x86_64-curl \
               mingw-w64-x86_64-wxPython \
               mingw-w64-x86_64-wxWidgets
     cd kicad-source
@@ -311,7 +303,6 @@ the following commands:
           -DCMAKE_PREFIX_PATH=/mingw64 \
           -DCMAKE_INSTALL_PREFIX=/mingw64 \
           -DDEFAULT_INSTALL_PATH=/mingw64 \
-          -DOPENSSL_ROOT_DIR=/mingw64 \
           -DKICAD_SKIP_BOOST=ON \
           -DKICAD_SCRIPTING=ON \
           -DKICAD_SCRIPTING_MODULES=ON \
@@ -408,7 +399,6 @@ Boost patches in the KiCad source [patch folder][].
 [wxWidgets]: http://wxwidgets.org/
 [patches folder]: http://bazaar.launchpad.net/~kicad-product-committers/kicad/product/files/head:/patches/
 [Boost]: http://www.boost.org/
-[OpenSSL]: https://www.openssl.org/
 [GLEW]: http://glew.sourceforge.net/
 [GLUT]: https://www.opengl.org/resources/libraries/glut/
 [Cairo]: http://cairographics.org/
diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt
index c9fbd29..e9c7e43 100644
--- a/common/CMakeLists.txt
+++ b/common/CMakeLists.txt
@@ -10,6 +10,12 @@ include_directories(
     ${INC_AFTER}
     )
 
+
+if( NOT APPLE )     # windows and linux use openssl under curl
+    find_package( OpenSSL REQUIRED )
+endif()
+
+
 # Generate header files containing shader programs
 # Order of input files is significant
 add_custom_command(
@@ -257,6 +263,9 @@ endif()
 
 set( COMMON_SRCS
     ${COMMON_SRCS}
+    kicad_curl/kicad_curl.cpp
+    kicad_curl/kicad_curl_easy.cpp
+
     view/view.cpp
     view/view_item.cpp
     view/view_group.cpp
@@ -282,7 +291,11 @@ set( COMMON_SRCS
 add_library( common STATIC ${COMMON_SRCS} )
 add_dependencies( common lib-dependencies )
 add_dependencies( common version_header )
-target_link_libraries( common ${Boost_LIBRARIES} )
+target_link_libraries( common
+    ${Boost_LIBRARIES}
+    ${CURL_LIBRARIES}
+    ${OPENSSL_LIBRARIES}        # empty on Apple
+    )
 
 
 set( PCB_COMMON_SRCS
diff --git a/common/basicframe.cpp b/common/basicframe.cpp
index 46ddd55..fad5e64 100644
--- a/common/basicframe.cpp
+++ b/common/basicframe.cpp
@@ -27,6 +27,14 @@
  * @file basicframe.cpp
  * @brief EDA_BASE_FRAME class implementation.
  */
+#include <config.h>
+
+// kicad_curl.h must be included before wx headers, to avoid
+// conflicts for some defines, at least on Windows
+#ifdef BUILD_GITHUB_PLUGIN
+#include <curl/curlver.h>
+#include <kicad_curl/kicad_curl.h>
+#endif
 
 #include <wx/aboutdlg.h>
 #include <wx/fontdlg.h>
@@ -580,6 +588,11 @@ void EDA_BASE_FRAME::CopyVersionInfoToClipboard( wxCommandEvent&  event )
                 << ( BOOST_VERSION / 100 % 1000 ) << wxT( "." )
                 << ( BOOST_VERSION % 100 ) << wxT( "\n" );
 
+#ifdef BUILD_GITHUB_PLUGIN
+    // Shows the Curl library version in use:
+    msg_version << "Curl version: " << KICAD_CURL::GetVersion() << "\n";
+#endif
+
     msg_version << wxT( "         USE_WX_GRAPHICS_CONTEXT=" );
 #ifdef USE_WX_GRAPHICS_CONTEXT
     msg_version << wxT( "ON\n" );
diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp
index 500e816..4d27c48 100644
--- a/common/footprint_info.cpp
+++ b/common/footprint_info.cpp
@@ -2,7 +2,7 @@
  * This program source code file is part of KiCad, a free EDA CAD application.
  *
  * Copyright (C) 2011 Jean-Pierre Charras, <jp.charras@xxxxxxxxxx>
- * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2013-2016 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
  * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  *
  * This program is free software; you can redistribute it and/or
@@ -28,7 +28,12 @@
  */
 
 
-#define USE_WORKER_THREADS      1       // 1:yes, 0:no. use worker thread to load libraries
+/**
+    No. concurrent threads doing "http(s) GET". More than 6 is not significantly
+    faster, less than 6 is likely slower. Main thread is in this count, so if
+    set to 1 then no temp threads are created.
+*/
+#define READER_THREADS      6
 
 /*
  * Functions to read footprint libraries and fill m_footprints by available footprints names
@@ -120,13 +125,6 @@ void FOOTPRINT_INFO::load()
 }
 
 
-#define JOBZ                6       // no. libraries per worker thread.  It takes about
-                                    // a second to load a GITHUB library, so assigning
-                                    // this no. libraries to each thread should give a little
-                                    // over this no. seconds total time if the original delay
-                                    // were caused by latencies alone.
-                                    // (If https://github.com does not mind.)
-
 void FOOTPRINT_LIST::loader_job( const wxString* aNicknameList, int aJobZ )
 {
     for( int i=0; i<aJobZ; ++i )
@@ -204,8 +202,6 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* a
         // do all of them
         nicknames = aTable->GetLogicalLibs();
 
-#if USE_WORKER_THREADS
-
         // Even though the PLUGIN API implementation is the place for the
         // locale toggling, in order to keep LOCAL_IO::C_count at 1 or greater
         // for the duration of all helper threads, we increment by one here via instantiation.
@@ -221,22 +217,23 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* a
 
         MYTHREADS threads;
 
+        unsigned jobz = (nicknames.size() + READER_THREADS - 1) / READER_THREADS;
+
         // Give each thread JOBZ nicknames to process.  The last portion of, or if the entire
         // size() is small, I'll do myself.
         for( unsigned i=0; i<nicknames.size();  )
         {
-            int jobz = JOBZ;
-
             if( i + jobz >= nicknames.size() )  // on the last iteration of this for(;;)
             {
                 jobz = nicknames.size() - i;
 
-                // Only a little bit to do, I'll do it myself, on current thread.
+                // Only a little bit to do, I'll do it myself on current thread.
+                // I am part of the READER_THREADS count.
                 loader_job( &nicknames[i], jobz );
             }
             else
             {
-                // Delegate the job to a worker thread created here.
+                // Delegate the job to a temporary thread created here.
                 threads.push_back( new boost::thread( &FOOTPRINT_LIST::loader_job,
                         this, &nicknames[i], jobz ) );
             }
@@ -251,9 +248,6 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* a
         {
             threads[i].join();
         }
-#else
-        loader_job( &nicknames[0], nicknames.size() );
-#endif
 
         m_list.sort();
     }
diff --git a/common/kicad_curl/kicad_curl.cpp b/common/kicad_curl/kicad_curl.cpp
new file mode 100644
index 0000000..fb4413c
--- /dev/null
+++ b/common/kicad_curl/kicad_curl.cpp
@@ -0,0 +1,224 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Mark Roszko <mark.roszko@xxxxxxxxx>
+ * Copyright (C) 2016 SoftPLC Corporation, Dick Hollenbeck <dick@xxxxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * 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 program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+// kicad_curl.h must be included before wx headers, to avoid
+// conflicts for some defines, at least on Windows
+#include <kicad_curl/kicad_curl.h>
+
+#include <wx/log.h>
+#include <wx/dynlib.h>
+
+#include <macros.h>
+#include <fctsys.h>
+#include <ki_mutex.h>       // MUTEX and MUTLOCK
+#include <richio.h>
+
+
+
+// These are even more private than class members, and since there is only
+// one instance of KICAD_CURL ever, these statics are hidden here to simplify the
+// client (API) header file.
+static volatile bool s_initialized;
+
+static MUTEX s_lock;        // for s_initialized
+
+// Assume that on these platforms libcurl uses OpenSSL
+#if defined(__linux__) || defined(__MINGW32__)
+
+#include <openssl/crypto.h>
+
+static MUTEX* s_crypto_locks;
+
+static void lock_callback( int mode, int type, const char* file, int line )
+{
+    (void)file;
+    (void)line;
+
+    wxASSERT( s_crypto_locks && unsigned( type ) < unsigned( CRYPTO_num_locks() ) );
+
+    //DBG( printf( "%s: mode=0x%x type=%d file=%s line=%d\n", __func__, mode, type, file, line );)
+
+    if( mode & CRYPTO_LOCK )
+    {
+        s_crypto_locks[ type ].lock();
+    }
+    else
+    {
+        s_crypto_locks[ type ].unlock();
+    }
+}
+
+
+static void init_locks()
+{
+    s_crypto_locks = new MUTEX[ CRYPTO_num_locks() ];
+
+    // From http://linux.die.net/man/3/crypto_set_id_callback:
+
+    /*
+
+    OpenSSL can safely be used in multi-threaded applications provided that at
+    least two callback functions are set, locking_function and threadid_func.
+
+    locking_function(int mode, int n, const char *file, int line) is needed to
+    perform locking on shared data structures. (Note that OpenSSL uses a number
+    of global data structures that will be implicitly shared whenever multiple
+    threads use OpenSSL.) Multi-threaded applications will crash at random if it
+    is not set.
+
+    threadid_func( CRYPTO_THREADID *id) is needed to record the
+    currently-executing thread's identifier into id. The implementation of this
+    callback should not fill in id directly, but should use
+    CRYPTO_THREADID_set_numeric() if thread IDs are numeric, or
+    CRYPTO_THREADID_set_pointer() if they are pointer-based. If the application
+    does not register such a callback using CRYPTO_THREADID_set_callback(), then
+    a default implementation is used - on Windows and BeOS this uses the
+    system's default thread identifying APIs, and on all other platforms it uses
+    the address of errno. The latter is satisfactory for thread-safety if and
+    only if the platform has a thread-local error number facility.
+
+    Dick: "sounds like CRYPTO_THREADID_set_callback() is not mandatory on our
+    2 OpenSSL platforms."
+
+    */
+
+    CRYPTO_set_locking_callback( &lock_callback );
+}
+
+
+static void kill_locks()
+{
+    CRYPTO_set_locking_callback( NULL );
+
+    delete[] s_crypto_locks;
+
+    s_crypto_locks = NULL;
+}
+
+#else
+
+inline void init_locks()    { /* dummy */ }
+inline void kill_locks()    { /* dummy */ }
+
+#endif
+
+/// At process termination, using atexit() keeps the CURL stuff out of the
+/// singletops and PGM_BASE.
+static void at_terminate()
+{
+    KICAD_CURL::Cleanup();
+}
+
+
+void KICAD_CURL::Init()
+{
+    // We test s_initialized twice in an effort to avoid
+    // unnecessarily locking s_lock.  This understands that the common case
+    // will not need to lock.
+    if( !s_initialized )
+    {
+        MUTLOCK lock( s_lock );
+
+        if( !s_initialized )
+        {
+            if( curl_global_init( CURL_GLOBAL_ALL ) != CURLE_OK )
+            {
+                THROW_IO_ERROR( "curl_global_init() failed." );
+            }
+
+            init_locks();
+
+            wxLogDebug( "Using %s", GetVersion() );
+
+            s_initialized = true;
+        }
+    }
+}
+
+
+void KICAD_CURL::Cleanup()
+{
+    /*
+
+    Calling MUTLOCK() from a static destructor will typically be bad, since the
+    s_lock may already have been statically destroyed itself leading to a boost
+    exception. (Remember C++ does not provide certain sequencing of static
+    destructor invocation.)
+
+    To prevent this we test s_initialized twice, which ensures that the MUTLOCK
+    is only instantiated on the first call, which should be from
+    PGM_BASE::destroy() which is first called earlier than static destruction.
+    Then when called again from the actual PGM_BASE::~PGM_BASE() function,
+    MUTLOCK will not be instantiated because s_initialized will be false.
+
+    */
+
+    if( s_initialized )
+    {
+        MUTLOCK lock( s_lock );
+
+        if( s_initialized )
+        {
+            curl_global_cleanup();
+
+            kill_locks();
+
+            atexit( &at_terminate );
+
+            s_initialized = false;
+        }
+    }
+}
+
+
+std::string KICAD_CURL::GetSimpleVersion()
+{
+    if( !s_initialized )
+        Init();
+
+    curl_version_info_data* info = curl_version_info( CURLVERSION_NOW );
+
+    std::string res;
+
+    if( info->version )
+    {
+        res += "libcurl version: " + std::string( info->version );
+    }
+
+    res += " (";
+
+    if( info->features & CURL_VERSION_SSL )
+    {
+        res += "with SSL - ";
+        res += std::string( info->ssl_version );
+    }
+    else
+    {
+        res += "without SSL";
+    }
+    res += ")";
+
+    return res;
+}
diff --git a/common/kicad_curl/kicad_curl_easy.cpp b/common/kicad_curl/kicad_curl_easy.cpp
new file mode 100644
index 0000000..1e84afe
--- /dev/null
+++ b/common/kicad_curl/kicad_curl_easy.cpp
@@ -0,0 +1,94 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Mark Roszko <mark.roszko@xxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * 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 program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include <kicad_curl/kicad_curl_easy.h>
+
+#include <cstddef>
+#include <exception>
+#include <stdarg.h>
+#include <sstream>
+#include <richio.h>
+
+
+static size_t write_callback( void* contents, size_t size, size_t nmemb, void* userp )
+{
+    size_t realsize = size * nmemb;
+
+    std::string* p = (std::string*) userp;
+
+    p->append( (const char*) contents, realsize );
+
+    return realsize;
+}
+
+
+KICAD_CURL_EASY::KICAD_CURL_EASY() :
+    m_headers( NULL )
+{
+    // Call KICAD_CURL::Init() from in here everytime, but only the first time
+    // will incur any overhead.  This strategy ensures that libcurl is never loaded
+    // unless it is needed.
+
+    KICAD_CURL::Init();
+
+    m_CURL = curl_easy_init();
+
+    if( !m_CURL )
+    {
+        THROW_IO_ERROR( "Unable to initialize CURL session" );
+    }
+
+    curl_easy_setopt( m_CURL, CURLOPT_WRITEFUNCTION, write_callback );
+    curl_easy_setopt( m_CURL, CURLOPT_WRITEDATA, (void*) &m_buffer );
+}
+
+
+KICAD_CURL_EASY::~KICAD_CURL_EASY()
+{
+    if( m_headers )
+        curl_slist_free_all( m_headers );
+
+    curl_easy_cleanup( m_CURL );
+}
+
+
+void KICAD_CURL_EASY::Perform()
+{
+    if( m_headers )
+    {
+        curl_easy_setopt( m_CURL, CURLOPT_HTTPHEADER, m_headers );
+    }
+
+    // bonus: retain worst case memory allocation, should re-use occur
+    m_buffer.clear();
+
+    CURLcode res = curl_easy_perform( m_CURL );
+
+    if( res != CURLE_OK )
+    {
+        std::string msg = StrPrintf( "curl_easy_perform()=%d: %s",
+                            res, GetErrorText( res ).c_str() );
+        THROW_IO_ERROR( msg );
+    }
+}
diff --git a/include/kicad_curl/kicad_curl.h b/include/kicad_curl/kicad_curl.h
new file mode 100644
index 0000000..51655a9
--- /dev/null
+++ b/include/kicad_curl/kicad_curl.h
@@ -0,0 +1,108 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Mark Roszko <mark.roszko@xxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * 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 program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+#ifndef KICAD_CURL_H_
+#define KICAD_CURL_H_
+
+/*
+ * KICAD_CURL.h must be included before wxWidgets because on Windows,
+ * wxWidgets ends up including windows.h before winsocks2.h inside curl
+ * this causes build warnings
+ * Because we are before wx, we must explicitly define we are building with unicode.
+ * wxWidgets defaults to supporting unicode now, so this should be safe.
+ */
+#if defined(WIN32)
+    #ifndef UNICODE
+    #    define UNICODE
+    #endif
+
+    #ifndef _UNICODE
+    #    define _UNICODE
+    #endif
+#endif
+
+#include <curl/curl.h>
+#include <string>
+
+// CURL_EXTERN expands to dllimport on MinGW which causes gcc warnings.  This really should
+// expand to nothing on MinGW.
+#if defined( __MINGW32__)
+#  if defined( CURL_EXTERN )
+#    undef CURL_EXTERN
+#    define CURL_EXTERN
+#  endif
+#endif
+
+
+struct DYN_LOOKUP;
+
+
+/**
+ * Class KICAD_CURL
+ * simple wrapper class to call curl_global_init and curl_global_cleanup for KiCad.
+ */
+class KICAD_CURL
+{
+    friend class KICAD_CURL_EASY;
+
+public:
+    /**
+     * Function Init
+     * calls curl_global_init for the application. It must be used only once
+     * and before any curl functions that perform requests.
+     *
+     * @return bool - True if successful, false if CURL returned an error
+     * @throw IO_ERROR on failure, hopefully with helpful text in it.
+     */
+    static void Init();
+
+    /**
+     * Function Cleanup
+     * calls curl_global_cleanup for the application. It must be used only after
+     * curl_global_init was called.
+     */
+    static void Cleanup();
+
+    /**
+     * Function GetVersion
+     * wrapper for curl_version(). Reports back a short string of loaded libraries.
+     *
+     * @return const char* - String reported by libcurl and owned by it.
+     * @throw IO_ERROR on failure, hopefully with helpful text in it.
+     */
+    static const char* GetVersion()
+    {
+        return curl_version();
+    }
+
+
+    /**
+     * Function GetSimpleVersion
+     * Reports back curl version only and SSL library support
+     *
+     * @return std::string - Generated version string
+     */
+    static std::string GetSimpleVersion();
+};
+
+#endif // KICAD_CURL_H_
diff --git a/include/kicad_curl/kicad_curl_easy.h b/include/kicad_curl/kicad_curl_easy.h
new file mode 100644
index 0000000..80d427c
--- /dev/null
+++ b/include/kicad_curl/kicad_curl_easy.h
@@ -0,0 +1,184 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Mark Roszko <mark.roszko@xxxxxxxxx>
+ * Copyright (C) 2015 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ *
+ * 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 program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+#ifndef KICAD_CURL_EASY_H_
+#define KICAD_CURL_EASY_H_
+
+/*
+ * KICAD_CURL_EASY.h must included before wxWidgets because on Windows,
+ * wxWidgets ends up including windows.h before winsocks2.h inside curl
+ * this causes build warnings
+ * Because we are before wx, we must explicitly define we are building with unicode
+ * wxWidgets defaults to supporting unicode now, so this should be safe.
+ */
+#if defined(WIN32)
+    #ifndef UNICODE
+    #    define UNICODE
+    #endif
+
+    #ifndef _UNICODE
+    #    define _UNICODE
+    #endif
+#endif
+
+
+#include <string>
+#include <curl/curl.h>
+#include <kicad_curl/kicad_curl.h>
+
+
+/**
+ * Class KICAD_CURL_EASY
+ * wrapper interface around the curl_easy API
+ *
+ * Handling of using the curl_easy API to make a request and save the response to
+ * a memory buffer
+ *
+ * Here is a small example usage:
+ * @code
+ *   KICAD_CURL_EASY curl;
+ *
+ *   curl.SetURL( "http://github.com"; );
+ *   curl.SetUserAgent( <http-client-indentifier> );
+ *   curl.SetHeader( "Accept", "application/json" );
+ *   curl.Perform();
+ * @endcode
+ */
+class KICAD_CURL_EASY
+{
+public:
+    KICAD_CURL_EASY();
+    ~KICAD_CURL_EASY();
+
+    /**
+     * Function perform
+     * equivalent to curl_easy_perform. Executes the request
+     * that was previously setup.
+     *
+     * @throw IO_ERROR, if there is a CURL request error
+     */
+    void Perform();
+
+    /**
+     * Function SetHeader
+     * sets an arbitrary header for the HTTP(s) request.
+     *
+     * @param aName is the left hand side of the header, i.e. Accept without the colon
+     * @param aValue is the right hand side of the header, i.e. application/json
+     */
+    void SetHeader( const std::string& aName, const std::string& aValue )
+    {
+        std::string header = aName + ':' + aValue;
+        m_headers = curl_slist_append( m_headers, header.c_str() );
+    }
+
+    /**
+     * Function SetUserAgent
+     * sets the request user agent
+     *
+     * @param aAgent is the string to set for the user agent
+     * @return bool - True if successful, false if not
+     */
+    bool SetUserAgent( const std::string& aAgent )
+    {
+        if( SetOption<const char*>( CURLOPT_USERAGENT, aAgent.c_str() ) == CURLE_OK )
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Function SetURL
+     * sets the request URL
+     *
+     * @param aURL is the URL
+     * @return bool - True if successful, false if not
+     */
+    bool SetURL( const std::string& aURL )
+    {
+        if( SetOption<const char *>( CURLOPT_URL, aURL.c_str() ) == CURLE_OK )
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Function SetFollowRedirects
+     * enables the following of HTTP(s) and other redirects, by default curl
+     * does not follow redirects.
+     *
+     * @param aFollow is a boolean where true will enable following redirects
+     * @return bool - True if successful, false if not
+     */
+    bool SetFollowRedirects( bool aFollow )
+    {
+        if( SetOption<long>( CURLOPT_FOLLOWLOCATION , (aFollow ? 1 : 0) ) == CURLE_OK )
+        {
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Function GetErrorText
+     * fetches CURL's "friendly" error string for a given error code
+     *
+     * @param aCode is CURL error code
+     * @return const std::string - the corresponding error string for the given code
+     */
+    const std::string GetErrorText( CURLcode aCode )
+    {
+        return curl_easy_strerror( aCode );
+    }
+
+    /**
+     * Function SetOption
+     * sets a curl option, only supports single parameter curl options
+     *
+     * @param aOption is CURL option, see CURL manual for options
+     * @param aArg is the argument being passed to CURL, ensure it is the right type per manual
+     * @return CURLcode - CURL error code, will return CURLE_OK unless a problem was encountered
+     */
+    template <typename T> CURLcode SetOption( CURLoption aOption, T aArg )
+    {
+        return curl_easy_setopt( m_CURL, aOption, aArg );
+    }
+
+    /**
+     * Function GetBuffer
+     * returns a const reference to the recevied data buffer
+     */
+    const std::string& GetBuffer()
+    {
+        return m_buffer;
+    }
+
+private:
+    CURL*           m_CURL;
+    curl_slist*     m_headers;
+    std::string     m_buffer;
+};
+
+#endif // KICAD_CURL_EASY_H_
diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt
index a0454be..acffe80 100644
--- a/pcbnew/CMakeLists.txt
+++ b/pcbnew/CMakeLists.txt
@@ -424,11 +424,11 @@ if( KICAD_SCRIPTING_MODULES )
         pcad2kicadpcb
         lib_dxf
         idf3
-        ${GITHUB_PLUGIN_LIBRARIES}
         polygon
         bitmaps
         gal
         ${wxWidgets_LIBRARIES}
+        ${GITHUB_PLUGIN_LIBRARIES}
         ${GDI_PLUS_LIBRARIES}
         ${PYTHON_LIBRARIES}
         ${PCBNEW_EXTRA_LIBS}
@@ -594,8 +594,8 @@ target_link_libraries( pcbnew_kiface
     gal
     lib_dxf
     idf3
-    ${GITHUB_PLUGIN_LIBRARIES}
     ${wxWidgets_LIBRARIES}
+    ${GITHUB_PLUGIN_LIBRARIES}
     ${GDI_PLUS_LIBRARIES}
     ${PYTHON_LIBRARIES}
     ${Boost_LIBRARIES}      # must follow GITHUB
diff --git a/pcbnew/github/CMakeLists.txt b/pcbnew/github/CMakeLists.txt
index d630c69..e9c8b9c 100644
--- a/pcbnew/github/CMakeLists.txt
+++ b/pcbnew/github/CMakeLists.txt
@@ -22,44 +22,21 @@
 
 
 
-# Download avhttp and install the headers, not actually compiled
-#################################################
-include( download_avhttp )
-
-if( MINGW AND NOT OPENSSL_ROOT_DIR )
-    # download, compile and install to scratch dir a recent OPENSSL library and headers
-    include( download_openssl )
-else()
-    find_package( OpenSSL REQUIRED )
-    #message( STATUS "OPENSSL_FOUND:${OPENSSL_FOUND}  OPENSSL_LIBRARIES:${OPENSSL_LIBRARIES}" )
-
-    # FindOpenSSL.cmake does not set this var into cache, so is not globally visible,
-    # do it here incase some other link image needs these libraries
-    set( OPENSSL_LIBRARIES   "${OPENSSL_LIBRARIES}"   CACHE FILEPATH "OpenSSL link libraries" )
-    set( OPENSSL_INCLUDE_DIR "${OPENSSL_INCLUDE_DIR}" CACHE FILEPATH "OpenSSL include dir" )
-endif()
-
-
 # These are additions to any inherited from pcbnew dir:
-include_directories( . ${OPENSSL_INCLUDE_DIR} ${AVHTTP_INCLUDE_DIR} )
-
-# Tell AVHTTP we have SSL.
-add_definitions( -DAVHTTP_ENABLE_OPENSSL )
+include_directories( . )
 
-# tone down the compiler warnings for avhttp header library:
-set( CMAKE_CXX_FLAGS
-    "${CMAKE_CXX_FLAGS} -Wno-sign-compare -Wno-reorder -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing" )
+include_directories( ${CURL_INCLUDE_DIRS} )
 
 set( GITHUB_PLUGIN_SRCS
-    github_plugin.cpp github_getliblist.cpp html_link_parser.cpp
+    github_plugin.cpp
+    github_getliblist.cpp
+    html_link_parser.cpp
     )
 
 add_library( github_plugin STATIC ${GITHUB_PLUGIN_SRCS} )
 
-# No, you don't get github without boost and openssl. Boost_LIBRARIES now moved up
-# into CMakeLists.txt for pcbnew and cvpcb:
 target_link_libraries( github_plugin
-    ${OPENSSL_LIBRARIES}
+    common
     )
 
 if( MINGW )
@@ -70,9 +47,4 @@ if( MINGW )
 endif()
 
 add_dependencies( github_plugin boost )
-add_dependencies( github_plugin avhttp )
-
-if( MINGW AND NOT OPENSSL_ROOT_DIR )
-    add_dependencies( github_plugin openssl )
-endif()
 
diff --git a/pcbnew/github/github_getliblist.cpp b/pcbnew/github/github_getliblist.cpp
index 00fcaca..07b3fb1 100644
--- a/pcbnew/github/github_getliblist.cpp
+++ b/pcbnew/github/github_getliblist.cpp
@@ -41,35 +41,7 @@
  *  JP Charras.
  */
 
-
-#if 0
-/*
- *  FIX ME
- *  I do not include avhttp.hpp here, because it is already included in
- *  github_plugin.cpp
- *  and if it is also included in this file, the link fails (double definiton of modules)
- *  therefore, the GITHUB_GETLIBLIST method which uses avhttp to download dats from gitub
- *  is in github_plugin.cpp
- */
-
-#ifndef WIN32_LEAN_AND_MEAN
-// when WIN32_LEAN_AND_MEAN is defined, some useless includes in <window.h>
-// are skipped, and this avoid some compil issues
-#define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifdef WIN32
-// defines needed by avhttp
-// Minimal Windows version is XP: Google for _WIN32_WINNT
- #define _WIN32_WINNT   0x0501
- #define WINVER         0x0501
-#endif
-
-#include <wx/wx.h>
-#include <avhttp.hpp>
-
-#endif
-
+#include <kicad_curl/kicad_curl_easy.h>     // Include before any wx file
 #include <wx/uri.h>
 
 #include <github_getliblist.h>
@@ -90,6 +62,7 @@ bool GITHUB_GETLIBLIST::Get3DshapesLibsList( wxArrayString* aList,
                         bool (*aFilter)( const wxString& aData ) )
 {
     std::string fullURLCommand;
+
     strcpy( m_option_string, "text/html" );
 
     wxString repoURL = m_repoURL;
@@ -97,7 +70,7 @@ bool GITHUB_GETLIBLIST::Get3DshapesLibsList( wxArrayString* aList,
     wxString errorMsg;
 
     fullURLCommand = repoURL.utf8_str();
-    bool success = remote_get_json( &fullURLCommand, &errorMsg );
+    bool success = remoteGetJSON( fullURLCommand, &errorMsg );
 
     if( !success )
     {
@@ -123,6 +96,7 @@ bool GITHUB_GETLIBLIST::GetFootprintLibraryList( wxArrayString& aList )
     std::string fullURLCommand;
     int page = 1;
     int itemCountMax = 99;              // Do not use a valu > 100, it does not work
+
     strcpy( m_option_string, "application/json" );
 
     // Github max items returned is 100 per page
@@ -147,7 +121,7 @@ bool GITHUB_GETLIBLIST::GetFootprintLibraryList( wxArrayString& aList )
 
     while( 1 )
     {
-        bool success = remote_get_json( &fullURLCommand, &errorMsg );
+        bool success = remoteGetJSON( fullURLCommand, &errorMsg );
 
         if( !success )
         {
@@ -235,3 +209,37 @@ bool GITHUB_GETLIBLIST::repoURL2listURL( const wxString& aRepoURL,
 
     return false;
 }
+
+
+bool GITHUB_GETLIBLIST::remoteGetJSON( const std::string& aFullURLCommand, wxString* aMsgError )
+{
+    KICAD_CURL_EASY kcurl;
+
+    wxLogDebug( wxT( "Attempting to download: " ) + aFullURLCommand );
+
+    kcurl.SetURL( aFullURLCommand );
+    kcurl.SetUserAgent( "http://kicad-pcb.org"; );
+    kcurl.SetHeader( "Accept", m_option_string );
+    kcurl.SetFollowRedirects( true );
+
+    try
+    {
+        kcurl.Perform();
+        m_image = kcurl.GetBuffer();
+        return true;
+    }
+    catch( const IO_ERROR& ioe )
+    {
+        if( aMsgError )
+        {
+            UTF8 fmt( _( "Error fetching JSON data from URL '%s'.\nReason: '%s'" ) );
+
+            std::string msg = StrPrintf( fmt.c_str(),
+                                         aFullURLCommand.c_str(),
+                                         TO_UTF8( ioe.errorText ) );
+
+            *aMsgError = FROM_UTF8( msg.c_str() );
+        }
+        return false;
+    }
+}
diff --git a/pcbnew/github/github_getliblist.h b/pcbnew/github/github_getliblist.h
index 6fd0598..0d38b8a 100644
--- a/pcbnew/github/github_getliblist.h
+++ b/pcbnew/github/github_getliblist.h
@@ -103,7 +103,7 @@ protected:
             int aItemCountMax, int aPage = 1 );
 
     /**
-     * Function remote_get_json
+     * Function remoteGetJSON
      * Download a json text from a github repo.  The text image
      * is received into the m_input_stream.
      * @param aFullURLCommand the full command, i.e. the url with options like
@@ -111,7 +111,7 @@ protected:
      * @param aMsgError a pointer to a wxString which can store an error message
      * @return true if OK, false if error (which an error message in *aMsgError
      */
-    bool remote_get_json( std::string* aFullURLCommand, wxString* aMsgError );
+    bool remoteGetJSON( const std::string& aFullURLCommand, wxString* aMsgError );
 
     wxString m_github_path;     ///< Something like https://api.github.com/orgs/KiCad
     std::string m_image;        ///< image of the downloaded data in its entirety.
diff --git a/pcbnew/github/github_plugin.cpp b/pcbnew/github/github_plugin.cpp
index 963a81c..0981083 100644
--- a/pcbnew/github/github_plugin.cpp
+++ b/pcbnew/github/github_plugin.cpp
@@ -38,8 +38,7 @@ I have lost my enthusiasm for local caching until a faster time stamp retrieval
 mechanism can be found, or github gets more servers.  But note that the occasionally
 slow response is the exception rather than the norm.  Normally the response is
 down around a 1/3 of a second.  The information we would use is in the header
-named "Last-Modified" as seen below.  This would need parsing, but avhttp may
-offer some help there, if not, then boost async probably does.
+named "Last-Modified" as seen below.
 
 
 HTTP/1.1 200 OK
@@ -62,23 +61,9 @@ Access-Control-Expose-Headers: ETag, Link, X-RateLimit-Limit, X-RateLimit-Remain
 Access-Control-Allow-Origin: *
 X-GitHub-Request-Id: 411087C2:659E:50FD6E6:52E67F66
 Vary: Accept-Encoding
-
 */
 
-
-#ifndef WIN32_LEAN_AND_MEAN
-// when WIN32_LEAN_AND_MEAN is defined, some useless includes in <window.h>
-// are skipped, and this avoid some compil issues
-#define WIN32_LEAN_AND_MEAN
-#endif
-
-#ifdef WIN32
- // defines needed by avhttp
- // Minimal Windows version is XP: Google for _WIN32_WINNT
- #define _WIN32_WINNT   0x0501
- #define WINVER         0x0501
-#endif
-
+#include <kicad_curl/kicad_curl_easy.h>     // Include before any wx file
 #include <sstream>
 #include <boost/ptr_container/ptr_map.hpp>
 #include <set>
@@ -88,10 +73,6 @@ Vary: Accept-Encoding
 #include <wx/uri.h>
 
 #include <fctsys.h>
-// Under Windows Mingw/msys, avhttp.hpp should be included after fctsys.h
-// in fact after wx/wx.h, included by fctsys.h,
-// to avoid issues (perhaps due to incompatible defines)
-#include <avhttp.hpp>                       // chinese SSL magic
 
 #include <io_mgr.h>
 #include <richio.h>
@@ -103,6 +84,7 @@ Vary: Accept-Encoding
 #include <fp_lib_table.h>       // ExpandSubstitutions()
 #include <github_getliblist.h>
 
+
 using namespace std;
 
 
@@ -139,7 +121,7 @@ GITHUB_PLUGIN::~GITHUB_PLUGIN()
 
 const wxString GITHUB_PLUGIN::PluginName() const
 {
-    return wxT( "Github" );
+    return "Github";
 }
 
 
@@ -212,7 +194,8 @@ MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
 
     if( it != m_gh_cache->end() )  // fp_name is present
     {
-        wxMemoryInputStream mis( &m_zip_image[0], m_zip_image.size() );
+        //std::string::data() ensures that the referenced data block is contiguous.
+        wxMemoryInputStream mis( m_zip_image.data(), m_zip_image.size() );
 
         // This decoder should always be UTF8, since it was saved that way by git.
         // That is, since pretty footprints are UTF8, and they were pushed to the
@@ -223,21 +206,17 @@ MODULE* GITHUB_PLUGIN::FootprintLoad( const wxString& aLibraryPath,
         if( zis.OpenEntry( *entry ) )
         {
             INPUTSTREAM_LINE_READER reader( &zis, aLibraryPath );
-#if 1
+
             // I am a PCB_IO derivative with my own PCB_PARSER
             m_parser->SetLineReader( &reader );     // ownership not passed
 
             MODULE* ret = (MODULE*) m_parser->Parse();
-#else
-            PCB_PARSER              parser( &reader );
 
-            MODULE* ret = (MODULE*) parser.Parse();
-#endif
-
-            // Dude, the footprint name comes from the file name in
-            // a github library.  Zero out the library name, we don't know it here.
-            // Some caller may set the library nickname, one such instance is
-            // FP_LIB_TABLE::FootprintLoad().
+            // In a github library, (as well as in a "KiCad" library) the name of
+            // the pretty file defines the footprint name.  That filename trumps
+            // any name found in the pretty file; any name in the pretty file
+            // must be ignored here.  Also, the library nickname is unknown in
+            // this context so clear it just in case.
             ret->SetFPID( fp_name );
 
             return ret;
@@ -408,7 +387,7 @@ void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aP
 
                 if( !wx_pretty_fn.IsOk() ||
                     !wx_pretty_fn.IsDirWritable() ||
-                    wx_pretty_fn.GetExt() != wxT( "pretty" )
+                    wx_pretty_fn.GetExt() != "pretty"
                   )
                 {
                     wxString msg = wxString::Format(
@@ -425,13 +404,13 @@ void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aP
         }
 
         // operator==( wxString, wxChar* ) does not exist, construct wxString once here.
-        const wxString    kicad_mod( wxT( "kicad_mod" ) );
+        const wxString    kicad_mod( "kicad_mod" );
 
         //D(printf("%s: this:%p  m_lib_path:'%s'  aLibraryPath:'%s'\n", __func__, this, TO_UTF8( m_lib_path), TO_UTF8(aLibraryPath) );)
         m_gh_cache = new GH_CACHE();
 
         // INIT_LOGGER( "/tmp", "test.log" );
-        remote_get_zip( aLibraryPath );
+        remoteGetZip( aLibraryPath );
         // UNINIT_LOGGER();
 
         m_lib_path = aLibraryPath;
@@ -460,7 +439,7 @@ void GITHUB_PLUGIN::cacheLib( const wxString& aLibraryPath, const PROPERTIES* aP
 }
 
 
-bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, string* aZipURL )
+bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL )
 {
     // e.g. "https://github.com/liftoff-sr/pretty_footprints";
     //D(printf("aRepoURL:%s\n", TO_UTF8( aRepoURL ) );)
@@ -470,12 +449,12 @@ bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, string* aZipURL )
     if( repo.HasServer() && repo.HasPath() )
     {
         // scheme might be "http" or if truly github.com then "https".
-        wxString zip_url = repo.GetScheme();
-
-        zip_url += "://";
+        wxString zip_url;
 
         if( repo.GetServer() == "github.com" )
         {
+            //codeload.github.com only supports https
+            zip_url = "https://";;
 #if 0       // A proper code path would be this one, but it is not the fastest.
             zip_url += repo.GetServer();
             zip_url += repo.GetPath();      // path comes with a leading '/'
@@ -488,8 +467,6 @@ bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, string* aZipURL )
 
             // In order to bypass this redirect, saving time, we use the
             // redirected URL on first attempt to save one HTTP GET hit.
-            // avhttp would do the redirect behind the scenes normally, but that would
-            // be slower than doing this bypass.
             zip_url += "codeload.github.com";
             zip_url += repo.GetPath();      // path comes with a leading '/'
             zip_url += "/zip/master";
@@ -498,9 +475,11 @@ bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, string* aZipURL )
 
         else
         {
+            zip_url = repo.GetScheme();
+            zip_url += "://";
+
             // This is the generic code path for any server which can serve
             // up zip files. The schemes tested include: http and https.
-            // (I don't know what the avhttp library supports beyond that.)
 
             // zip_url goal: "<scheme>://<server>[:<port>]/<path>"
 
@@ -533,9 +512,9 @@ bool GITHUB_PLUGIN::repoURL_zipURL( const wxString& aRepoURL, string* aZipURL )
 }
 
 
-void GITHUB_PLUGIN::remote_get_zip( const wxString& aRepoURL ) throw( IO_ERROR )
+void GITHUB_PLUGIN::remoteGetZip( const wxString& aRepoURL ) throw( IO_ERROR )
 {
-    string  zip_url;
+    std::string  zip_url;
 
     if( !repoURL_zipURL( aRepoURL, &zip_url ) )
     {
@@ -543,107 +522,48 @@ void GITHUB_PLUGIN::remote_get_zip( const wxString& aRepoURL ) throw( IO_ERROR )
         THROW_IO_ERROR( msg );
     }
 
-    boost::asio::io_service io;
-    avhttp::http_stream     h( io );
-    avhttp::request_opts    options;
+    wxLogDebug( wxT( "Attempting to download: " ) + zip_url );
 
-    options.insert( "Accept",       "application/zip" );
-    options.insert( "User-Agent",   "http://kicad-pcb.org"; );   // THAT WOULD BE ME.
-    h.request_options( options );
+    KICAD_CURL_EASY kcurl;      // this can THROW_IO_ERROR
+
+    kcurl.SetURL( zip_url.c_str() );
+    kcurl.SetUserAgent( "http://kicad-pcb.org"; );
+    kcurl.SetHeader( "Accept", "application/zip" );
+    kcurl.SetFollowRedirects( true );
 
     try
     {
-        ostringstream os;
-
-        h.open( zip_url );      // only one file, therefore do it synchronously.
-        os << &h;
-
-        // Keep zip file byte image in RAM.  That plus the MODULE_MAP will constitute
-        // the cache.  We don't cache the MODULEs per se, we parse those as needed from
-        // this zip file image.
-        m_zip_image = os.str();
-
-        // 4 lines, using SSL, top that.
+        kcurl.Perform();
+        m_zip_image = kcurl.GetBuffer();
     }
-    catch( const boost::system::system_error& e )
+    catch( const IO_ERROR& ioe )
     {
-        // https "GET" has faild, report this to API caller.
+        // https "GET" has failed, report this to API caller.
+        // Note: kcurl.Perform() does not return an error if the file to download is not found
         static const char errorcmd[] = "http GET command failed";  // Do not translate this message
 
         UTF8 fmt( _( "%s\nCannot get/download Zip archive: '%s'\nfor library path: '%s'.\nReason: '%s'" ) );
 
-        string msg = StrPrintf( fmt.c_str(),
-                errorcmd,
-                // Report both secret zip_url and Lib Path, to user.  The secret
-                // zip_url may go bad at some point in future if github changes
-                // their server architecture.  Then fix repoURL_zipURL() to reflect
-                // new architecture.
-                zip_url.c_str(), TO_UTF8( aRepoURL ),
-                e.what() );
-
-        THROW_IO_ERROR( msg );
-    }
-    catch( const exception& exc )
-    {
-        UTF8 error( _( "Exception '%s' in avhttp while open()-ing URI:'%s'" ) );
+        std::string msg = StrPrintf( fmt.c_str(),
+                                     errorcmd,
+                                     zip_url.c_str(),
+                                     TO_UTF8( aRepoURL ),
+                                     TO_UTF8( ioe.errorText )
+                                     );
 
-        string msg = StrPrintf( error.c_str(), exc.what(), zip_url.c_str() );
         THROW_IO_ERROR( msg );
     }
-}
-
 
-// This GITHUB_GETLIBLIST method should not be here, but in github_getliblist.cpp !
-// However it is here just because we need to include <avhttp.hpp> to compile it.
-// and when we include avhttp in two .cpp files, the link fails because it detects duplicate
-// avhttp functions.
-// So until it is fixed, this code is here.
-bool GITHUB_GETLIBLIST::remote_get_json( std::string* aFullURLCommand, wxString* aMsgError )
-{
-    boost::asio::io_service io;
-    avhttp::http_stream     h( io );
-    avhttp::request_opts    options;
-
-
-    options.insert( "Accept", m_option_string );
-    options.insert( "User-Agent", "http://kicad-pcb.org"; );   // THAT WOULD BE ME.
-    h.request_options( options );
-
-    try
+    // If the zip archive is not existing, the received data is "Not Found" or "404: Not Found",
+    // and no error is returned by kcurl.Perform().
+    if( ( m_zip_image.compare( 0, 9, "Not Found", 9 ) == 0 ) ||
+        ( m_zip_image.compare( 0, 14, "404: Not Found", 14 ) == 0 ) )
     {
-        std::ostringstream os;
-
-        h.open( *aFullURLCommand );      // only one file, therefore do it synchronously.
-        os << &h;
+        UTF8 fmt( _( "Cannot download library '%s'.\nThe library does not exist on the server" ) );
+        std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
 
-        // Keep downloaded text file image in RAM.
-        m_image = os.str();
-
-        // 4 lines, using SSL, top that.
-    }
-    catch( boost::system::system_error& e )
-    {
-        // https "GET" has faild, report this to API caller.
-        static const char errorcmd[] = "https GET command failed";  // Do not translate this message
-
-        UTF8 fmt( _( "%s\nCannot get/download data from: '%s'\nReason: '%s'" ) );
-
-        std::string msg = StrPrintf( fmt.c_str(),
-                errorcmd,
-                // Report secret list_url to user.  The secret
-                // list_url may go bad at some point in future if github changes
-                // their server architecture.  Then fix repoURL_zipURL() to reflect
-                // new architecture.
-                aFullURLCommand->c_str(), e.what() );
-
-        if( aMsgError )
-        {
-            *aMsgError = FROM_UTF8( msg.c_str() );
-            return false;
-        }
+        THROW_IO_ERROR( msg );
     }
-
-    return true;
 }
 
 #if 0 && defined(STANDALONE)
@@ -657,7 +577,7 @@ int main( int argc, char** argv )
     try
     {
         wxArrayString fps = gh.FootprintEnumerate(
-                wxT( "https://github.com/liftoff-sr/pretty_footprints"; ),
+                "https://github.com/liftoff-sr/pretty_footprints";,
                 NULL
                 );
 
diff --git a/pcbnew/github/github_plugin.h b/pcbnew/github/github_plugin.h
index 4bb8248..92f2c13 100644
--- a/pcbnew/github/github_plugin.h
+++ b/pcbnew/github/github_plugin.h
@@ -213,11 +213,11 @@ protected:
     static bool repoURL_zipURL( const wxString& aRepoURL, std::string* aZipURL );
 
     /**
-     * Function remote_get_zip
+     * Function remoteGetZip
      * fetches a zip file image from a github repo synchronously.  The byte image
      * is received into the m_input_stream.
      */
-    void remote_get_zip( const wxString& aRepoURL ) throw( IO_ERROR );
+    void remoteGetZip( const wxString& aRepoURL ) throw( IO_ERROR );
 
     wxString    m_lib_path;     ///< from aLibraryPath, something like https://github.com/liftoff-sr/pretty_footprints
     std::string m_zip_image;    ///< byte image of the zip file in its entirety.
-- 
1.9.5.msysgit.1


Follow ups