Try to replace avhttp by Curl

This commit is contained in:
jean-pierre charras 2016-12-07 18:43:57 +01:00
parent 5127a6bd09
commit 981fddc649
16 changed files with 758 additions and 299 deletions

View File

@ -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 #
######################

View File

@ -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@softplc.com>
# 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 )

View File

@ -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/

View File

@ -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

View File

@ -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" );

View File

@ -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@wanadoo.fr>
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013-2016 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* 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();
}

View File

@ -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@gmail.com>
* Copyright (C) 2016 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* 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;
}

View File

@ -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@gmail.com>
* 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 );
}
}

View File

@ -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@gmail.com>
* 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_

View File

@ -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@gmail.com>
* 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_

View File

@ -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

View File

@ -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} )
include_directories( . )
# Tell AVHTTP we have SSL.
add_definitions( -DAVHTTP_ENABLE_OPENSSL )
# 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()

View File

@ -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;
}
}

View File

@ -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.

View File

@ -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'" ) );
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
{
std::ostringstream os;
h.open( *aFullURLCommand ); // only one file, therefore do it synchronously.
os << &h;
// 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() );
errorcmd,
zip_url.c_str(),
TO_UTF8( aRepoURL ),
TO_UTF8( ioe.errorText )
);
if( aMsgError )
{
*aMsgError = FROM_UTF8( msg.c_str() );
return false;
}
THROW_IO_ERROR( msg );
}
return true;
// 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 ) )
{
UTF8 fmt( _( "Cannot download library '%s'.\nThe library does not exist on the server" ) );
std::string msg = StrPrintf( fmt.c_str(), TO_UTF8( aRepoURL ) );
THROW_IO_ERROR( msg );
}
}
#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
);

View File

@ -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.