├── CHANGES ├── include ├── curl-asio │ ├── native.h │ ├── initialization.h │ ├── config.h │ ├── string_list.h │ ├── socket_info.h │ ├── share.h │ ├── form.h │ ├── multi.h │ ├── error_code.h │ └── easy.h └── curl-asio.h ├── src ├── string_list.cpp ├── initialization.cpp ├── CMakeLists.txt ├── share.cpp ├── error_code.cpp ├── form.cpp ├── multi.cpp └── easy.cpp ├── examples ├── CMakeLists.txt ├── synchronous.cpp └── asynchronous.cpp ├── COPYING ├── cmake ├── FindCURLASIO.cmake └── FindCURLASIO-CURL.cmake ├── README.md └── CMakeLists.txt /CHANGES: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include/curl-asio/native.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Native libcurl API 7 | */ 8 | 9 | #pragma once 10 | 11 | namespace curl { 12 | namespace native { 13 | 14 | #include 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /include/curl-asio.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include "curl-asio/config.h" 10 | #include "curl-asio/easy.h" 11 | #include "curl-asio/error_code.h" 12 | #include "curl-asio/form.h" 13 | #include "curl-asio/initialization.h" 14 | #include "curl-asio/multi.h" 15 | #include "curl-asio/share.h" 16 | #include "curl-asio/string_list.h" 17 | -------------------------------------------------------------------------------- /include/curl-asio/initialization.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Helper to automatically initialize and cleanup libcurl resources 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | 14 | namespace curl 15 | { 16 | class initialization 17 | { 18 | public: 19 | typedef boost::shared_ptr ptr; 20 | static ptr ensure_initialization(); 21 | ~initialization(); 22 | protected: 23 | initialization(); 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /include/curl-asio/config.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | */ 6 | 7 | #pragma once 8 | 9 | #if !defined CURLASIO_API 10 | # if defined _MSC_VER 11 | # if defined CURLASIO_STATIC 12 | # define CURLASIO_API 13 | # elif defined libcurlasio_EXPORTS 14 | # define CURLASIO_API __declspec(dllexport) 15 | # else 16 | # define CURLASIO_API __declspec(dllimport) 17 | # endif 18 | # else 19 | # define CURLASIO_API 20 | # endif 21 | #endif 22 | 23 | // Disable unused boost components. If your program depends on any of these 24 | // components, include them prior to including curl-asio. 25 | #ifndef BOOST_ASIO_DISABLE_BOOST_REGEX 26 | # define BOOST_ASIO_DISABLE_BOOST_REGEX 27 | #endif 28 | -------------------------------------------------------------------------------- /src/string_list.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for libcurl's string list interface 7 | */ 8 | 9 | #include 10 | 11 | using namespace curl; 12 | 13 | string_list::string_list(): 14 | list_(0) 15 | { 16 | initref_ = initialization::ensure_initialization(); 17 | } 18 | 19 | string_list::~string_list() 20 | { 21 | if (list_) 22 | { 23 | native::curl_slist_free_all(list_); 24 | list_ = 0; 25 | } 26 | } 27 | 28 | void string_list::add(const char* str) 29 | { 30 | native::curl_slist* p = native::curl_slist_append(list_, str); 31 | 32 | if (!p) 33 | { 34 | throw std::bad_alloc(); 35 | } 36 | 37 | list_ = p; 38 | } 39 | 40 | void string_list::add(const std::string& str) 41 | { 42 | add(str.c_str()); 43 | } 44 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # curl-asio 2 | # Seamlessly integrate libcurl with Boost.Asio 3 | # 4 | # Copyright (c) 2013 Oliver Kuckertz 5 | # See COPYING for license information. 6 | 7 | INCLUDE_DIRECTORIES( 8 | ${CURLASIO_INCLUDE_DIR} 9 | ${CURL_INCLUDE_DIR} 10 | ${Boost_INCLUDE_DIRS} 11 | ) 12 | 13 | macro(ADD_EXAMPLE EXAMPLE_NAME) 14 | SET(EXAMPLE_PROJECT_NAME "${EXAMPLE_NAME}_example") 15 | SET(EXAMPLE_SOURCE_FILES "${EXAMPLE_NAME}.cpp") 16 | ADD_EXECUTABLE(${EXAMPLE_PROJECT_NAME} ${EXAMPLE_SOURCE_FILES}) 17 | ADD_DEFINITIONS(${EXAMPLE_PROJECT_DEFINITIONS}) 18 | LINK_DIRECTORIES(${Boost_LIBRARY_DIR}) 19 | TARGET_LINK_LIBRARIES(${EXAMPLE_PROJECT_NAME} 20 | ${EXAMPLE_LINK_TARGET} 21 | ${CURL_LIBRARIES} 22 | ${Boost_LIBRARIES} 23 | ) 24 | IF(CURLASIO_STATICLIB) 25 | TARGET_LINK_LIBRARIES(${EXAMPLE_PROJECT_NAME} ${CURL_LIBRARIES}) 26 | ENDIF() 27 | endmacro() 28 | 29 | ADD_EXAMPLE(asynchronous) 30 | ADD_EXAMPLE(synchronous) 31 | -------------------------------------------------------------------------------- /include/curl-asio/string_list.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Constructs libcurl string lists 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include 14 | #include 15 | #include "initialization.h" 16 | #include "native.h" 17 | 18 | namespace curl 19 | { 20 | class CURLASIO_API string_list: 21 | public boost::enable_shared_from_this, 22 | public boost::noncopyable 23 | { 24 | public: 25 | string_list(); 26 | ~string_list(); 27 | 28 | inline native::curl_slist* native_handle() { return list_; } 29 | 30 | void add(const char* str); 31 | void add(const std::string& str); 32 | 33 | private: 34 | initialization::ptr initref_; 35 | native::curl_slist* list_; 36 | }; 37 | } 38 | -------------------------------------------------------------------------------- /include/curl-asio/socket_info.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace curl 15 | { 16 | typedef boost::asio::ip::tcp::socket socket_type; 17 | 18 | class easy; 19 | 20 | struct socket_info : public boost::enable_shared_from_this 21 | { 22 | socket_info(easy* _handle, std::auto_ptr _socket): 23 | handle(_handle), 24 | socket(_socket), 25 | pending_read_op(false), 26 | pending_write_op(false), 27 | monitor_read(false), 28 | monitor_write(false) 29 | { 30 | } 31 | 32 | easy* handle; 33 | boost::scoped_ptr socket; 34 | bool pending_read_op; 35 | bool pending_write_op; 36 | bool monitor_read; 37 | bool monitor_write; 38 | }; 39 | } 40 | -------------------------------------------------------------------------------- /examples/synchronous.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char* argv[]) 6 | { 7 | // expect two arguments 8 | if (argc != 3) 9 | { 10 | std::cerr << "usage: " << argv[0] << " url file" << std::endl; 11 | return 1; 12 | } 13 | 14 | // this example program downloads argv[1] to argv[2] 15 | char* url = argv[1]; 16 | char* file_name = argv[2]; 17 | 18 | // start by creating an io_service object 19 | boost::asio::io_service io_service; 20 | 21 | // construct an instance of curl::easy 22 | curl::easy downloader(io_service); 23 | 24 | // set the object's properties 25 | downloader.set_url(url); 26 | downloader.set_sink(boost::make_shared(file_name, std::ios::binary)); 27 | 28 | // download the file 29 | boost::system::error_code ec; 30 | downloader.perform(ec); 31 | 32 | // error handling 33 | if (!ec) 34 | { 35 | std::cerr << "Download succeeded" << std::endl; 36 | } 37 | else 38 | { 39 | std::cerr << "Download failed: " << ec.message() << std::endl; 40 | } 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | This project (curl-asio) is a library which cannot function without libcurl. 2 | In order to grant you the same freedoms libcurl offers, curl-asio is licensed 3 | under the same MIT/X derivate license used by libcurl at the time of writing 4 | this library. 5 | 6 | curl-asio 7 | Copyright (c) 2013 Oliver Kuckertz 8 | 9 | All rights reserved. 10 | 11 | Permission to use, copy, modify, and distribute this software for any purpose 12 | with or without fee is hereby granted, provided that the above copyright 13 | notice and this permission notice appear in all copies. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN 18 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 19 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 20 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE 21 | OR OTHER DEALINGS IN THE SOFTWARE. 22 | 23 | Except as contained in this notice, the name of a copyright holder shall not 24 | be used in advertising or otherwise to promote the sale, use or other dealings 25 | in this Software without prior written authorization of the copyright holder. 26 | -------------------------------------------------------------------------------- /src/initialization.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Helper to automatically initialize and cleanup libcurl resources 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace curl; 16 | 17 | boost::weak_ptr helper_instance; 18 | boost::mutex helper_lock; 19 | 20 | initialization::ptr initialization::ensure_initialization() 21 | { 22 | ptr result = helper_instance.lock(); 23 | 24 | if (!result) 25 | { 26 | boost::lock_guard lock(helper_lock); 27 | result = helper_instance.lock(); 28 | 29 | if (!result) 30 | { 31 | result = boost::shared_ptr(new initialization()); 32 | helper_instance = result; 33 | } 34 | } 35 | 36 | return result; 37 | } 38 | 39 | initialization::initialization() 40 | { 41 | native::CURLcode ec = native::curl_global_init(CURL_GLOBAL_DEFAULT); 42 | 43 | if (ec != native::CURLE_OK) 44 | { 45 | throw std::runtime_error("curl_global_init failed with error code " + boost::lexical_cast(ec)); 46 | } 47 | } 48 | 49 | initialization::~initialization() 50 | { 51 | native::curl_global_cleanup(); 52 | } 53 | -------------------------------------------------------------------------------- /include/curl-asio/share.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for libcurl's share interface 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include 14 | #include 15 | #include "initialization.h" 16 | #include "native.h" 17 | 18 | namespace curl 19 | { 20 | class CURLASIO_API share: 21 | public boost::enable_shared_from_this, 22 | public boost::noncopyable 23 | { 24 | public: 25 | share(); 26 | ~share(); 27 | 28 | inline native::CURLSH* native_handle() { return handle_; } 29 | void set_share_cookies(bool enabled); 30 | void set_share_dns(bool enabled); 31 | void set_share_ssl_session(bool enabled); 32 | 33 | typedef void (*lock_function_t)(native::CURL* handle, native::curl_lock_data data, native::curl_lock_access access, void* userptr); 34 | void set_lock_function(lock_function_t lock_function); 35 | 36 | typedef void (*unlock_function_t)(native::CURL* handle, native::curl_lock_data data, void* userptr); 37 | void set_unlock_function(unlock_function_t unlock_function); 38 | 39 | void set_user_data(void* user_data); 40 | 41 | private: 42 | static void lock(native::CURL* handle, native::curl_lock_data data, native::curl_lock_access access, void* userptr); 43 | static void unlock(native::CURL* handle, native::curl_lock_data data, void* userptr); 44 | 45 | initialization::ptr initref_; 46 | native::CURLSH* handle_; 47 | boost::mutex mutex_; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # curl-asio 2 | # Seamlessly integrate libcurl with Boost.Asio 3 | # 4 | # Copyright (c) 2013 Oliver Kuckertz 5 | # See COPYING for license information. 6 | 7 | INCLUDE_DIRECTORIES( 8 | ${CURLASIO_INCLUDE_DIR} 9 | ${CURL_INCLUDE_DIR} 10 | ${Boost_INCLUDE_DIRS} 11 | ) 12 | 13 | # Collect all source files 14 | SET(LIBCURLASIO_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}") 15 | FILE(GLOB LIBCURLASIO_SOURCE_FILES "${LIBCURLASIO_SOURCE_DIR}/*.cpp") 16 | 17 | # Collect all header files 18 | SET(LIBCURLASIO_HEADER_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../include") 19 | FILE(GLOB LIBCURLASIO_HEADER_FILES "${LIBCURLASIO_HEADER_DIR}/curl-asio/*.h") 20 | LIST(APPEND LIBCURLASIO_HEADER_FILES "${LIBCURLASIO_HEADER_DIR}/curl-asio.h") 21 | 22 | # Install targets 23 | SET(LIBCURLASIO_INSTALL_TARGETS) 24 | 25 | # Build the shared library 26 | IF(BUILD_SHARED) 27 | ADD_LIBRARY( 28 | curlasio-shared 29 | SHARED 30 | ${LIBCURLASIO_SOURCE_FILES} 31 | ${LIBCURLASIO_HEADER_FILES} 32 | ) 33 | TARGET_LINK_LIBRARIES(curlasio-shared 34 | ${CURL_LIBRARIES} 35 | ${Boost_LIBRARIES} 36 | ) 37 | SET_TARGET_PROPERTIES(curlasio-shared PROPERTIES 38 | DEBUG_POSTFIX d 39 | OUTPUT_NAME curlasio 40 | ) 41 | LIST(APPEND LIBCURLASIO_INSTALL_TARGETS curlasio-shared) 42 | ENDIF() 43 | 44 | # Build the static library 45 | IF(BUILD_STATIC) 46 | ADD_DEFINITIONS(-DCURLASIO_STATIC) 47 | ADD_LIBRARY( 48 | curlasio-static 49 | STATIC 50 | ${LIBCURLASIO_SOURCE_FILES} 51 | ${LIBCURLASIO_HEADER_FILES} 52 | ) 53 | SET_TARGET_PROPERTIES(curlasio-static PROPERTIES 54 | DEBUG_POSTFIX d 55 | OUTPUT_NAME curlasio 56 | ) 57 | LIST(APPEND LIBCURLASIO_INSTALL_TARGETS curlasio-static) 58 | ENDIF() 59 | 60 | # Install all libraries/archives to $PREFIX/lib (and DLLs to $PREFIX/bin on Windows) 61 | INSTALL(TARGETS ${LIBCURLASIO_INSTALL_TARGETS} 62 | RUNTIME DESTINATION bin 63 | LIBRARY DESTINATION lib 64 | ARCHIVE DESTINATION lib 65 | ) 66 | 67 | # Install header files to $PREFIX/include 68 | INSTALL(DIRECTORY "${LIBCURLASIO_HEADER_DIR}/" DESTINATION include) 69 | -------------------------------------------------------------------------------- /cmake/FindCURLASIO.cmake: -------------------------------------------------------------------------------- 1 | # Find curl-asio 2 | # Oliver Kuckertz , 2013-10-06, public domain 3 | # 4 | # Searches for: 5 | # /include/curl-asio.h 6 | # curlasio.lib or libcurlasio.lib 7 | # curlasiod.lib or libcurlasiod.lib 8 | # 9 | # Defines: 10 | # CURLASIO_INCLUDE_DIR 11 | # CURLASIO_LIBRARIES 12 | # 13 | # Uses: 14 | # CURLASIO_ROOT 15 | # CURLASIO_STATIC 16 | # 17 | 18 | FIND_PATH(CURLASIO_INCLUDE_DIR NAMES curl-asio.h HINTS ${CURLASIO_ROOT} PATH_SUFFIXES include) 19 | MARK_AS_ADVANCED(CURLASIO_INCLUDE_DIR) 20 | 21 | OPTION(CURLASIO_STATIC "Use the static curl-asio library." ON) 22 | MARK_AS_ADVANCED(CURLASIO_STATIC) 23 | 24 | IF(CURLASIO_STATIC) 25 | SET(CURLASIO_LIBRARY_NAME curlasio) 26 | ELSE() 27 | SET(CURLASIO_LIBRARY_NAME libcurlasio) 28 | ENDIF() 29 | 30 | FIND_LIBRARY(CURLASIO_LIBRARY_DEBUG "${CURLASIO_LIBRARY_NAME}d" HINTS ${CURLASIO_ROOT} PATH_SUFFIXES lib) 31 | FIND_LIBRARY(CURLASIO_LIBRARY_RELEASE "${CURLASIO_LIBRARY_NAME}" HINTS ${CURLASIO_ROOT} PATH_SUFFIXES lib) 32 | MARK_AS_ADVANCED(CURLASIO_LIBRARY_DEBUG CURLASIO_LIBRARY_RELEASE) 33 | 34 | IF(CURLASIO_LIBRARY_DEBUG AND NOT CURLASIO_LIBRARY_RELEASE) 35 | SET(CURLASIO_LIBRARIES ${CURLASIO_LIBRARY_DEBUG}) 36 | ELSEIF(NOT CURLASIO_LIBRARY_DEBUG AND CURLASIO_LIBRARY_RELEASE) 37 | SET(CURLASIO_LIBRARIES ${CURLASIO_LIBRARY_RELEASE}) 38 | ELSE() 39 | SET(CURLASIO_LIBRARIES) 40 | IF(CURLASIO_LIBRARY_DEBUG) 41 | LIST(APPEND CURLASIO_LIBRARIES debug ${CURLASIO_LIBRARY_DEBUG}) 42 | SET(CURLASIO_LIBRARY_DEBUG_FOUND TRUE) 43 | ENDIF() 44 | IF(CURLASIO_LIBRARY_RELEASE) 45 | LIST(APPEND CURLASIO_LIBRARIES optimized ${CURLASIO_LIBRARY_RELEASE}) 46 | SET(CURLASIO_LIBRARY_RELEASE_FOUND TRUE) 47 | ENDIF() 48 | ENDIF() 49 | 50 | FIND_PACKAGE(CURLASIO-CURL REQUIRED) 51 | SET(CURLASIO_INCLUDE_DIRS ${CURLASIO_INCLUDE_DIR} ${CURL_INCLUDE_DIR}) 52 | 53 | IF(CURLASIO_STATIC) 54 | LIST(APPEND CURLASIO_LIBRARIES ${CURL_LIBRARIES}) 55 | ENDIF() 56 | 57 | INCLUDE(FindPackageHandleStandardArgs) 58 | 59 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURLASIO 60 | REQUIRED_VARS 61 | CURLASIO_INCLUDE_DIR 62 | CURLASIO_LIBRARIES 63 | FAIL_MESSAGE 64 | "Could not find curl-asio, ensure it is in either the system's or CMake's path, or set CURLASIO_ROOT." 65 | ) 66 | -------------------------------------------------------------------------------- /examples/asynchronous.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include // for std::auto_ptr 8 | 9 | boost::ptr_set active_downloads; 10 | 11 | void handle_download_completed(const boost::system::error_code& err, std::string url, curl::easy* easy) 12 | { 13 | if (!err) 14 | { 15 | std::cout << "Download of " << url << " completed" << std::endl; 16 | } 17 | else 18 | { 19 | std::cout << "Download of " << url << " failed: " << err.message() << std::endl; 20 | } 21 | 22 | active_downloads.erase(*easy); 23 | } 24 | 25 | void start_download(curl::multi& multi, const std::string& url) 26 | { 27 | std::auto_ptr easy(new curl::easy(multi)); 28 | 29 | // see 'Use server-provided file names' example for a more detailed implementation of this function which receives 30 | // the target file name from the server using libcurl's header callbacks 31 | std::string file_name = url.substr(url.find_last_of('/') + 1); 32 | 33 | easy->set_url(url); 34 | easy->set_sink(boost::make_shared(file_name.c_str(), std::ios::binary)); 35 | easy->async_perform(boost::bind(handle_download_completed, boost::asio::placeholders::error, url, easy.get())); 36 | 37 | active_downloads.insert(easy); 38 | } 39 | 40 | int main(int argc, char* argv[]) 41 | { 42 | // expect one argument 43 | if (argc != 2) 44 | { 45 | std::cerr << "usage: " << argv[0] << " url-list-file" << std::endl; 46 | return 1; 47 | } 48 | 49 | // this example program downloads all urls in the text file argv[1] to the current directory 50 | char* url_file_name = argv[1]; 51 | 52 | // start by creating an io_service object 53 | boost::asio::io_service io_service; 54 | 55 | // construct an instance of curl::multi 56 | curl::multi manager(io_service); 57 | 58 | // treat each line in url_file_name as url and start a download from it 59 | std::ifstream url_file(url_file_name); 60 | while (!url_file.eof()) 61 | { 62 | std::string url; 63 | std::getline(url_file, url); 64 | start_download(manager, url); 65 | } 66 | 67 | // let Boost.Asio do its magic 68 | io_service.run(); 69 | 70 | std::cout << "All downloads completed" << std::endl; 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /include/curl-asio/form.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for constructing libcurl forms 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include 14 | #include 15 | #include "initialization.h" 16 | #include "native.h" 17 | 18 | namespace curl 19 | { 20 | class CURLASIO_API form: 21 | public boost::enable_shared_from_this
, 22 | public boost::noncopyable 23 | { 24 | public: 25 | form(); 26 | ~form(); 27 | 28 | inline native::curl_httppost* native_handle() { return post_; }; 29 | 30 | void add_content(const std::string& key, const std::string& content); 31 | void add_content(const std::string& key, const std::string& content, boost::system::error_code& ec); 32 | void add_content(const std::string& key, const std::string& content, const std::string& content_type); 33 | void add_content(const std::string& key, const std::string& content, const std::string& content_type, boost::system::error_code& ec); 34 | void add_file(const std::string& key, const std::string& file_path); 35 | void add_file(const std::string& key, const std::string& file_path, boost::system::error_code& ec); 36 | void add_file(const std::string& key, const std::string& file_path, const std::string& content_type); 37 | void add_file(const std::string& key, const std::string& file_path, const std::string& content_type, boost::system::error_code& ec); 38 | void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name); 39 | void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, boost::system::error_code& ec); 40 | void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type); 41 | void add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type, boost::system::error_code& ec); 42 | void add_file_content(const std::string& key, const std::string& file_path); 43 | void add_file_content(const std::string& key, const std::string& file_path, boost::system::error_code& ec); 44 | void add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type); 45 | void add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type, boost::system::error_code& ec); 46 | 47 | private: 48 | initialization::ptr initref_; 49 | native::curl_httppost* post_; 50 | native::curl_httppost* last_; 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /src/share.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for libcurl's share interface 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace curl; 14 | 15 | share::share() 16 | { 17 | initref_ = initialization::ensure_initialization(); 18 | handle_ = native::curl_share_init(); 19 | 20 | if (!handle_) 21 | { 22 | throw std::bad_alloc(); 23 | } 24 | 25 | set_lock_function(&share::lock); 26 | set_unlock_function(&share::unlock); 27 | set_user_data(this); 28 | } 29 | 30 | share::~share() 31 | { 32 | if (handle_) 33 | { 34 | native::curl_share_cleanup(handle_); 35 | handle_ = 0; 36 | } 37 | } 38 | 39 | void share::set_share_cookies(bool enabled) 40 | { 41 | boost::system::error_code ec(native::curl_share_setopt(handle_, enabled ? native::CURLSHOPT_SHARE : native::CURLSHOPT_UNSHARE, native::CURL_LOCK_DATA_COOKIE)); 42 | boost::asio::detail::throw_error(ec); 43 | } 44 | 45 | void share::set_share_dns(bool enabled) 46 | { 47 | boost::system::error_code ec(native::curl_share_setopt(handle_, enabled ? native::CURLSHOPT_SHARE : native::CURLSHOPT_UNSHARE, native::CURL_LOCK_DATA_DNS)); 48 | boost::asio::detail::throw_error(ec); 49 | } 50 | 51 | void share::set_share_ssl_session(bool enabled) 52 | { 53 | boost::system::error_code ec(native::curl_share_setopt(handle_, enabled ? native::CURLSHOPT_SHARE : native::CURLSHOPT_UNSHARE, native::CURL_LOCK_DATA_SSL_SESSION)); 54 | boost::asio::detail::throw_error(ec); 55 | } 56 | 57 | void share::set_lock_function(lock_function_t lock_function) 58 | { 59 | boost::system::error_code ec(native::curl_share_setopt(handle_, native::CURLSHOPT_LOCKFUNC, lock_function)); 60 | boost::asio::detail::throw_error(ec); 61 | } 62 | 63 | void share::set_unlock_function(unlock_function_t unlock_function) 64 | { 65 | boost::system::error_code ec(native::curl_share_setopt(handle_, native::CURLSHOPT_UNLOCKFUNC, unlock_function)); 66 | boost::asio::detail::throw_error(ec); 67 | } 68 | 69 | void share::set_user_data(void* user_data) 70 | { 71 | boost::system::error_code ec(native::curl_share_setopt(handle_, native::CURLSHOPT_USERDATA, user_data)); 72 | boost::asio::detail::throw_error(ec); 73 | } 74 | 75 | void share::lock(native::CURL* handle, native::curl_lock_data data, native::curl_lock_access access, void* userptr) 76 | { 77 | share* self = static_cast(userptr); 78 | self->mutex_.lock(); 79 | } 80 | 81 | void share::unlock(native::CURL* handle, native::curl_lock_data data, void* userptr) 82 | { 83 | share* self = static_cast(userptr); 84 | self->mutex_.unlock(); 85 | } 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Note (2018): This library is currently unmaintained and a rewrite for C++14/17, possibly as simple header-only library, is planned. 2 | 3 | curl-asio 4 | ========= 5 | 6 | **Here be dragons. Although this library generally works quite well, it is still being developed and has not been extensively tested.** You will probably be fine, but don't look at me when things catch fire. 7 | 8 | This library makes use of libcurl's multi interface in order to enable easy integration into Boost.Asio applications. 9 | 10 | * **simple interface** - Download and upload anything, synchronously or asynchronously, with just a few lines of code. 11 | * **familiar** - If you have used libcurl in a C application before, you will feel right at home. 12 | * **exceptions** - Libcurl errors throw exceptions. Integrates nicely with Boost.System's error_code class. 13 | * **useful wrappers** - C++ interfaces for libcurl's easy, multi, form, share and string list containers. All setopt calls are wrapped for type safety. 14 | * **source/sink concept** - Works nicely with Boost.Iostreams 15 | 16 | Installation 17 | ------------ 18 | 1. If not already done, install cURL and its header files 19 | 2. Clone this git repository. There are no tags or packages yet. 20 | 3. Run CMake and point it to cURL 21 | 4. `make && make install` 22 | 23 | Example 24 | ------- 25 | 26 | ```c++ 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | int main(int argc, char* argv[]) 33 | { 34 | // this example program downloads argv[1] to argv[2] (arg validation omitted for readability) 35 | char* url = argv[1]; 36 | char* file_name = argv[2]; 37 | 38 | // start by creating an io_service object 39 | boost::asio::io_service io_service; 40 | 41 | // construct an instance of curl::easy 42 | curl::easy downloader(io_service); 43 | 44 | // set the object's properties 45 | downloader.set_url(url); 46 | downloader.set_sink(boost::make_shared(file_name, std::ios::binary)); 47 | 48 | // download the file 49 | boost::system::error_code ec; 50 | downloader.perform(ec); 51 | 52 | // error handling 53 | if (!ec) 54 | { 55 | std::cerr << "Download succeeded" << std::endl; 56 | } 57 | else 58 | { 59 | std::cerr << "Download failed: " << ec.message() << std::endl; 60 | } 61 | 62 | return 0; 63 | } 64 | ``` 65 | 66 | More examples, including one for curl-asio's [asynchronous interface](https://github.com/mologie/curl-asio/wiki/Asynchronous-interface), can be found in the [wiki](https://github.com/mologie/curl-asio/wiki) and the `examples` directory. 67 | 68 | Todo 69 | ---- 70 | 71 | * Testing suite based on libcurl's tests 72 | * API documentation, design documentation, more examples 73 | * Support for transport schemes using UDP and incoming TCP sockets (active FTP) 74 | * File upload streams 75 | * string_list iterators 76 | 77 | License 78 | ------- 79 | Curl-asio is licensed under the same MIT/X derivate license used by libcurl. 80 | -------------------------------------------------------------------------------- /cmake/FindCURLASIO-CURL.cmake: -------------------------------------------------------------------------------- 1 | # Find libcurl 2 | # Oliver Kuckertz , 2013-10-06, public domain 3 | # 4 | # This is a lightweight replacement for CMake's FindCURL.cmake, dropping 5 | # support for older libcurl libraries, adding a switch for static library 6 | # support, and allowing to link to debug versions of libcurl. 7 | # 8 | # Searches for: 9 | # /include/curl/curl.h 10 | # libcurl.lib 11 | # libcurld.lib 12 | # 13 | # Defines: 14 | # CURL_INCLUDE_DIR 15 | # CURL_LIBRARIES 16 | # CURL_VERSION 17 | # 18 | # Uses: 19 | # CURL_ROOT 20 | # CURL_STATIC 21 | # 22 | 23 | FIND_PATH(CURL_INCLUDE_DIR NAMES curl/curl.h HINTS ${CURL_ROOT} PATH_SUFFIXES include) 24 | MARK_AS_ADVANCED(CURL_INCLUDE_DIR) 25 | 26 | OPTION(CURL_STATIC "Use the static curl library." ON) 27 | MARK_AS_ADVANCED(CURL_STATIC) 28 | 29 | IF(CURL_STATIC) 30 | ADD_DEFINITIONS(-DCURL_STATICLIB) 31 | ENDIF() 32 | 33 | IF(MSVC) 34 | IF(CURL_STATIC) 35 | SET(CURL_LIBRARY_NAME libcurl) 36 | ELSE() 37 | SET(CURL_LIBRARY_NAME libcurl_imp) 38 | ENDIF() 39 | ELSE() 40 | IF(CURL_STATIC) 41 | SET(CURL_LIBRARY_NAME curl) 42 | ELSE() 43 | SET(CURL_LIBRARY_NAME libcurl) 44 | ENDIF() 45 | ENDIF() 46 | 47 | FIND_LIBRARY(CURL_LIBRARY_DEBUG "${CURL_LIBRARY_NAME}d" HINTS ${CURL_ROOT} PATH_SUFFIXES lib) 48 | FIND_LIBRARY(CURL_LIBRARY_RELEASE "${CURL_LIBRARY_NAME}" HINTS ${CURL_ROOT} PATH_SUFFIXES lib) 49 | MARK_AS_ADVANCED(CURL_LIBRARY_DEBUG CURL_LIBRARY_RELEASE) 50 | 51 | IF(CURL_LIBRARY_DEBUG AND NOT CURL_LIBRARY_RELEASE) 52 | SET(CURL_LIBRARIES ${CURL_LIBRARY_DEBUG}) 53 | ELSEIF(NOT CURL_LIBRARY_DEBUG AND CURL_LIBRARY_RELEASE) 54 | SET(CURL_LIBRARIES ${CURL_LIBRARY_RELEASE}) 55 | ELSE() 56 | SET(CURL_LIBRARIES) 57 | IF(CURL_LIBRARY_DEBUG) 58 | LIST(APPEND CURL_LIBRARIES debug ${CURL_LIBRARY_DEBUG}) 59 | SET(CURL_LIBRARY_DEBUG_FOUND TRUE) 60 | ENDIF() 61 | IF(CURL_LIBRARY_RELEASE) 62 | LIST(APPEND CURL_LIBRARIES optimized ${CURL_LIBRARY_RELEASE}) 63 | SET(CURL_LIBRARY_RELEASE_FOUND TRUE) 64 | ENDIF() 65 | ENDIF() 66 | 67 | # If only the debug or only the release library was found, use it for all configurations 68 | IF(CURL_LIBRAY_RELEASE_FOUND AND NOT CURL_LIBRARY_DEBUG_FOUND) 69 | SET(CURL_LIBRARIES ${CURL_LIBRARY_RELEASE}) 70 | ELSEIF(CURL_LIBRARY_DEBUG_FOUND AND NOT CURL_LIBRARY_RELEASE_FOUND) 71 | SET(CURL_LIBRARIES ${CURL_LIBRARY_DEBUG}) 72 | ENDIF() 73 | 74 | SET(_CURL_VERSION_FILE "${CURL_INCLUDE_DIR}/curl/curl.h") 75 | IF(EXISTS ${_CURL_VERSION_FILE}) 76 | FILE(STRINGS ${_CURL_VERSION_FILE} _CURL_VERSION_LINE REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"") 77 | STRING(REGEX REPLACE ".*\"(.*)\".*" "\\1" CURL_VERSION "${_CURL_VERSION_LINE}") 78 | ELSE() 79 | SET(CURL_VERSION "unknown") 80 | ENDIF() 81 | 82 | INCLUDE(FindPackageHandleStandardArgs) 83 | 84 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(CURL 85 | REQUIRED_VARS 86 | CURL_INCLUDE_DIR 87 | CURL_LIBRARIES 88 | VERSION_VAR 89 | CURL_VERSION 90 | FAIL_MESSAGE 91 | "Could not find libcurl, ensure it is in either the system's or CMake's path, or set CURL_ROOT." 92 | ) 93 | -------------------------------------------------------------------------------- /include/curl-asio/multi.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Integration of libcurl's multi interface with Boost.Asio 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include "initialization.h" 19 | #include "native.h" 20 | #include "socket_info.h" 21 | 22 | namespace curl 23 | { 24 | class easy; 25 | 26 | class CURLASIO_API multi: 27 | public boost::noncopyable 28 | { 29 | public: 30 | multi(boost::asio::io_service& io_service); 31 | ~multi(); 32 | 33 | inline boost::asio::io_service& get_io_service() { return io_service_; } 34 | inline native::CURLM* native_handle() { return handle_; } 35 | 36 | void add(easy* easy_handle); 37 | void remove(easy* easy_handle); 38 | 39 | void socket_register(boost::shared_ptr si); 40 | void socket_cleanup(native::curl_socket_t s); 41 | 42 | private: 43 | typedef boost::shared_ptr socket_info_ptr; 44 | 45 | void add_handle(native::CURL* native_easy); 46 | void remove_handle(native::CURL* native_easy); 47 | 48 | void assign(native::curl_socket_t sockfd, void* user_data); 49 | void socket_action(native::curl_socket_t s, int event_bitmask); 50 | 51 | typedef int (*socket_function_t)(native::CURL* native_easy, native::curl_socket_t s, int what, void* userp, void* socketp); 52 | void set_socket_function(socket_function_t socket_function); 53 | void set_socket_data(void* socket_data); 54 | 55 | typedef int (*timer_function_t)(native::CURLM* native_multi, long timeout_ms, void* userp); 56 | void set_timer_function(timer_function_t timer_function); 57 | void set_timer_data(void* timer_data); 58 | 59 | void monitor_socket(socket_info_ptr si, int action); 60 | void process_messages(); 61 | bool still_running(); 62 | 63 | void start_read_op(socket_info_ptr si); 64 | void handle_socket_read(const boost::system::error_code& err, socket_info_ptr si); 65 | void start_write_op(socket_info_ptr si); 66 | void handle_socket_write(const boost::system::error_code& err, socket_info_ptr si); 67 | void handle_timeout(const boost::system::error_code& err); 68 | 69 | typedef boost::asio::ip::tcp::socket socket_type; 70 | typedef std::map socket_map_type; 71 | socket_map_type sockets_; 72 | socket_info_ptr get_socket_from_native(native::curl_socket_t native_socket); 73 | 74 | static int socket(native::CURL* native_easy, native::curl_socket_t s, int what, void* userp, void* socketp); 75 | static int timer(native::CURLM* native_multi, long timeout_ms, void* userp); 76 | 77 | typedef std::set easy_set_type; 78 | 79 | boost::asio::io_service& io_service_; 80 | initialization::ptr initref_; 81 | native::CURLM* handle_; 82 | easy_set_type easy_handles_; 83 | boost::asio::deadline_timer timeout_; 84 | int still_running_; 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # curl-asio 2 | # Seamlessly integrate libcurl with Boost.Asio 3 | # 4 | # Copyright (c) 2013 Oliver Kuckertz 5 | # See COPYING for license information. 6 | 7 | CMAKE_MINIMUM_REQUIRED(VERSION 2.6.2 FATAL_ERROR) 8 | PROJECT(curl-asio) 9 | 10 | # Adjust the module path 11 | LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") 12 | 13 | # Build options 14 | OPTION(BUILD_STATIC "Build the static library" ON) 15 | OPTION(BUILD_SHARED "Build the shared library" OFF) 16 | OPTION(BUILD_EXAMPLES "Build the examples" ON) 17 | 18 | IF(NOT MSVC) 19 | OPTION(ENABLE_CPP11 "Enable features and examples which require C++11" ON) 20 | IF(ENABLE_CPP11) 21 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++") 22 | FOREACH(_PROPERTY_NAME CMAKE_EXE_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS CMAKE_MODULE_LINKER_FLAGS) 23 | SET(${_PROPERTY_NAME} "${${_PROPERTY_NAME}} -stdlib=libc++") 24 | ENDFOREACH() 25 | ENDIF() 26 | ENDIF() 27 | 28 | IF(NOT BUILD_STATIC AND NOT BUILD_SHARED) 29 | MESSAGE(FATAL_ERROR "Neither BUILD_STATIC nor BUILD_SHARED is set") 30 | ENDIF() 31 | 32 | SET(CURLASIO_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") 33 | 34 | # Prefer the shared interface over the static for building examples 35 | IF(BUILD_SHARED) 36 | SET(EXAMPLE_LINK_TARGET curlasio-shared) 37 | ELSE() 38 | SET(EXAMPLE_LINK_TARGET curlasio-static) 39 | SET(EXAMPLE_PROJECT_DEFINITIONS -DCURLASIO_STATIC) 40 | ENDIF() 41 | 42 | IF(MSVC) 43 | # Select Windows version 44 | OPTION(ENABLE_VISTA_FEATURES "Enable Vista features. This disables some workarounds, but sacrifices Windows XP compatibility." OFF) 45 | IF(ENABLE_VISTA_FEATURES) 46 | SET(TARGET_WINDOWS_VERSION 0x0600) 47 | ELSE() 48 | SET(TARGET_WINDOWS_VERSION 0x0501) 49 | ENDIF() 50 | ADD_DEFINITIONS(-D_WIN32_WINNT=${TARGET_WINDOWS_VERSION}) 51 | 52 | # Disable using __declspec(dllimport) when linking statically 53 | OPTION(CURL_IS_STATIC "Check if libcurl is a static library" OFF) 54 | IF(CURL_IS_STATIC) 55 | ADD_DEFINITIONS(-DCURL_STATICLIB) 56 | ENDIF() 57 | ENDIF() 58 | 59 | # Find dependencies 60 | FIND_PACKAGE(CURLASIO-CURL REQUIRED) 61 | FIND_PACKAGE(Boost REQUIRED COMPONENTS chrono date_time system thread) 62 | 63 | # Move along 64 | ADD_SUBDIRECTORY(src) 65 | IF(BUILD_EXAMPLES) 66 | ADD_SUBDIRECTORY(examples) 67 | ENDIF() 68 | 69 | # Install CMake modules for curl-asio and libcurl 70 | OPTION(INSTALL_CMAKE_MODULES "Install CMake module files for libcurl and curl-asio" ON) 71 | IF(INSTALL_CMAKE_MODULES) 72 | IF(APPLE) 73 | IF((IS_SYMLINK "${CMAKE_INSTALL_PREFIX}/share/cmake") OR (IS_SYMLINK "${CMAKE_INSTALL_PREFIX}/share/cmake/Modules")) 74 | MESSAGE(FATAL_ERROR "The destination path `${CMAKE_INSTALL_PREFIX}/share/cmake' is a symlink. " 75 | "If you are using Homebrew, run the following set of commands prior to installing this library:\n" 76 | " brew unlink cmake\n" 77 | " mkdir -p '${CMAKE_INSTALL_PREFIX}/share/cmake/Modules'\n" 78 | " brew link cmake\n" 79 | "Without these changes, updating CMake through Homebrew would break the installation. Alternatively, choose a different CMAKE_INSTALL_PREFIX.") 80 | ENDIF() 81 | ENDIF() 82 | INSTALL(DIRECTORY cmake/ DESTINATION share/cmake/Modules) 83 | ENDIF() 84 | -------------------------------------------------------------------------------- /src/error_code.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Integration of libcurl's error codes (CURLcode) into boost.system's error_code class 7 | */ 8 | 9 | #include 10 | 11 | using namespace curl; 12 | 13 | class curl_easy_error_category : public boost::system::error_category 14 | { 15 | public: 16 | curl_easy_error_category() { } 17 | const char* name() const BOOST_NOEXCEPT; 18 | std::string message(int ev) const; 19 | }; 20 | 21 | const char* curl_easy_error_category::name() const BOOST_NOEXCEPT 22 | { 23 | return "curl-easy"; 24 | } 25 | 26 | std::string curl_easy_error_category::message(int ev) const 27 | { 28 | return native::curl_easy_strerror(static_cast(ev)); 29 | } 30 | 31 | class curl_multi_error_category : public boost::system::error_category 32 | { 33 | public: 34 | curl_multi_error_category() { } 35 | const char* name() const BOOST_NOEXCEPT; 36 | std::string message(int ev) const; 37 | }; 38 | 39 | const char* curl_multi_error_category::name() const BOOST_NOEXCEPT 40 | { 41 | return "curl-multi"; 42 | } 43 | 44 | std::string curl_multi_error_category::message(int ev) const 45 | { 46 | return native::curl_multi_strerror(static_cast(ev)); 47 | } 48 | 49 | class curl_share_error_category : public boost::system::error_category 50 | { 51 | public: 52 | curl_share_error_category() { } 53 | const char* name() const BOOST_NOEXCEPT; 54 | std::string message(int ev) const; 55 | }; 56 | 57 | const char* curl_share_error_category::name() const BOOST_NOEXCEPT 58 | { 59 | return "curl-share"; 60 | } 61 | 62 | std::string curl_share_error_category::message(int ev) const 63 | { 64 | return native::curl_share_strerror(static_cast(ev)); 65 | } 66 | 67 | class curl_form_error_category : public boost::system::error_category 68 | { 69 | public: 70 | curl_form_error_category() { } 71 | const char* name() const BOOST_NOEXCEPT; 72 | std::string message(int ev) const; 73 | }; 74 | 75 | const char* curl_form_error_category::name() const BOOST_NOEXCEPT 76 | { 77 | return "curl-form"; 78 | } 79 | 80 | std::string curl_form_error_category::message(int ev) const 81 | { 82 | switch (static_cast(ev)) 83 | { 84 | case errc::form::success: 85 | return "no error"; 86 | 87 | case errc::form::memory: 88 | return "memory allocation error"; 89 | 90 | case errc::form::option_twice: 91 | return "one option is given twice"; 92 | 93 | case errc::form::null: 94 | return "a null pointer was given for a char"; 95 | 96 | case errc::form::unknown_option: 97 | return "an unknown option was used"; 98 | 99 | case errc::form::incomplete: 100 | return "some FormInfo is not complete (or error)"; 101 | 102 | case errc::form::illegal_array: 103 | return "an illegal option is used in an array"; 104 | 105 | case errc::form::disabled: 106 | return "form support was disabled"; 107 | 108 | default: 109 | return "no error description (unknown CURLFORMcode)"; 110 | } 111 | } 112 | 113 | const boost::system::error_category& errc::get_easy_category() BOOST_NOEXCEPT 114 | { 115 | static const curl_easy_error_category curl_easy_category_const; 116 | return curl_easy_category_const; 117 | } 118 | 119 | const boost::system::error_category& errc::get_multi_category() BOOST_NOEXCEPT 120 | { 121 | static const curl_multi_error_category curl_multi_category_const; 122 | return curl_multi_category_const; 123 | } 124 | 125 | const boost::system::error_category& errc::get_share_category() BOOST_NOEXCEPT 126 | { 127 | static const curl_share_error_category curl_share_category_const; 128 | return curl_share_category_const; 129 | } 130 | 131 | const boost::system::error_category& errc::get_form_category() BOOST_NOEXCEPT 132 | { 133 | static const curl_form_error_category curl_form_category_const; 134 | return curl_form_category_const; 135 | } 136 | -------------------------------------------------------------------------------- /src/form.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for constructing libcurl forms 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace curl; 14 | 15 | form::form(): 16 | post_(0), 17 | last_(0) 18 | { 19 | initref_ = initialization::ensure_initialization(); 20 | } 21 | 22 | form::~form() 23 | { 24 | if (post_) 25 | { 26 | native::curl_formfree(post_); 27 | post_ = 0; 28 | } 29 | } 30 | 31 | void form::add_content(const std::string& key, const std::string& content) 32 | { 33 | boost::system::error_code ec; 34 | add_content(key, content, ec); 35 | boost::asio::detail::throw_error(ec, "add_content"); 36 | } 37 | 38 | void form::add_content(const std::string& key, const std::string& content, boost::system::error_code& ec) 39 | { 40 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 41 | native::CURLFORM_COPYNAME, key.c_str(), 42 | native::CURLFORM_NAMELENGTH, key.length(), 43 | native::CURLFORM_COPYCONTENTS, content.c_str(), 44 | native::CURLFORM_CONTENTSLENGTH, content.length(), 45 | native::CURLFORM_END 46 | )); 47 | } 48 | 49 | void form::add_content(const std::string& key, const std::string& content, const std::string& content_type) 50 | { 51 | boost::system::error_code ec; 52 | add_content(key, content, content_type, ec); 53 | boost::asio::detail::throw_error(ec, "add_content"); 54 | } 55 | 56 | void form::add_content(const std::string& key, const std::string& content, const std::string& content_type, boost::system::error_code& ec) 57 | { 58 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 59 | native::CURLFORM_COPYNAME, key.c_str(), 60 | native::CURLFORM_NAMELENGTH, key.length(), 61 | native::CURLFORM_COPYCONTENTS, content.c_str(), 62 | native::CURLFORM_CONTENTSLENGTH, content.length(), 63 | native::CURLFORM_CONTENTTYPE, content_type.c_str(), 64 | native::CURLFORM_END 65 | )); 66 | } 67 | 68 | void form::add_file(const std::string& key, const std::string& file_path) 69 | { 70 | boost::system::error_code ec; 71 | add_file(key, file_path, ec); 72 | boost::asio::detail::throw_error(ec, "add_file"); 73 | } 74 | 75 | void form::add_file(const std::string& key, const std::string& file_path, boost::system::error_code& ec) 76 | { 77 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 78 | native::CURLFORM_COPYNAME, key.c_str(), 79 | native::CURLFORM_NAMELENGTH, key.length(), 80 | native::CURLFORM_FILE, file_path.c_str(), 81 | native::CURLFORM_END 82 | )); 83 | } 84 | 85 | void form::add_file(const std::string& key, const std::string& file_path, const std::string& content_type) 86 | { 87 | boost::system::error_code ec; 88 | add_file(key, file_path, content_type, ec); 89 | boost::asio::detail::throw_error(ec, "add_file"); 90 | } 91 | 92 | void form::add_file(const std::string& key, const std::string& file_path, const std::string& content_type, boost::system::error_code& ec) 93 | { 94 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 95 | native::CURLFORM_COPYNAME, key.c_str(), 96 | native::CURLFORM_NAMELENGTH, key.length(), 97 | native::CURLFORM_FILE, file_path.c_str(), 98 | native::CURLFORM_CONTENTTYPE, content_type.c_str(), 99 | native::CURLFORM_END 100 | )); 101 | } 102 | 103 | void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name) 104 | { 105 | boost::system::error_code ec; 106 | add_file_using_name(key, file_path, file_name, ec); 107 | boost::asio::detail::throw_error(ec, "add_file_using_name"); 108 | } 109 | 110 | void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, boost::system::error_code& ec) 111 | { 112 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 113 | native::CURLFORM_COPYNAME, key.c_str(), 114 | native::CURLFORM_NAMELENGTH, key.length(), 115 | native::CURLFORM_FILE, file_path.c_str(), 116 | native::CURLFORM_FILENAME, file_name.c_str(), 117 | native::CURLFORM_END 118 | )); 119 | } 120 | 121 | void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type) 122 | { 123 | boost::system::error_code ec; 124 | add_file_using_name(key, file_path, file_name, content_type, ec); 125 | boost::asio::detail::throw_error(ec, "add_file_using_name"); 126 | } 127 | 128 | void form::add_file_using_name(const std::string& key, const std::string& file_path, const std::string& file_name, const std::string& content_type, boost::system::error_code& ec) 129 | { 130 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 131 | native::CURLFORM_COPYNAME, key.c_str(), 132 | native::CURLFORM_NAMELENGTH, key.length(), 133 | native::CURLFORM_FILE, file_path.c_str(), 134 | native::CURLFORM_FILENAME, file_name.c_str(), 135 | native::CURLFORM_CONTENTTYPE, content_type.c_str(), 136 | native::CURLFORM_END 137 | )); 138 | } 139 | 140 | void form::add_file_content(const std::string& key, const std::string& file_path) 141 | { 142 | boost::system::error_code ec; 143 | add_file_content(key, file_path, ec); 144 | boost::asio::detail::throw_error(ec, "add_file_content"); 145 | } 146 | 147 | void form::add_file_content(const std::string& key, const std::string& file_path, boost::system::error_code& ec) 148 | { 149 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 150 | native::CURLFORM_COPYNAME, key.c_str(), 151 | native::CURLFORM_NAMELENGTH, key.length(), 152 | native::CURLFORM_FILECONTENT, file_path.c_str(), 153 | native::CURLFORM_END 154 | )); 155 | } 156 | 157 | void form::add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type) 158 | { 159 | boost::system::error_code ec; 160 | add_file_content(key, file_path, content_type, ec); 161 | boost::asio::detail::throw_error(ec, "add_file_content"); 162 | } 163 | 164 | void form::add_file_content(const std::string& key, const std::string& file_path, const std::string& content_type, boost::system::error_code& ec) 165 | { 166 | ec = boost::system::error_code(native::curl_formadd(&post_, &last_, 167 | native::CURLFORM_COPYNAME, key.c_str(), 168 | native::CURLFORM_NAMELENGTH, key.length(), 169 | native::CURLFORM_FILECONTENT, file_path.c_str(), 170 | native::CURLFORM_CONTENTTYPE, content_type.c_str(), 171 | native::CURLFORM_END 172 | )); 173 | } 174 | -------------------------------------------------------------------------------- /include/curl-asio/error_code.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Integration of libcurl's error codes (CURLcode) into boost.system's error_code class 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include "native.h" 14 | 15 | namespace curl 16 | { 17 | namespace errc 18 | { 19 | namespace easy 20 | { 21 | enum easy_error_codes 22 | { 23 | success = native::CURLE_OK, 24 | unsupported_protocol = native::CURLE_UNSUPPORTED_PROTOCOL, 25 | failed_init = native::CURLE_FAILED_INIT, 26 | url_malformat = native::CURLE_URL_MALFORMAT, 27 | not_built_in = native::CURLE_NOT_BUILT_IN, 28 | could_not_resolve_proxy = native::CURLE_COULDNT_RESOLVE_PROXY, 29 | could_not_resovle_host = native::CURLE_COULDNT_RESOLVE_HOST, 30 | could_not_connect = native::CURLE_COULDNT_CONNECT, 31 | ftp_weird_server_reply = native::CURLE_FTP_WEIRD_SERVER_REPLY, 32 | remote_access_denied = native::CURLE_REMOTE_ACCESS_DENIED, 33 | ftp_accept_failed = native::CURLE_FTP_ACCEPT_FAILED, 34 | ftp_weird_pass_reply = native::CURLE_FTP_WEIRD_PASS_REPLY, 35 | ftp_accept_timeout = native::CURLE_FTP_ACCEPT_TIMEOUT, 36 | ftp_weird_pasv_reply = native::CURLE_FTP_WEIRD_PASV_REPLY, 37 | ftp_weird_227_format = native::CURLE_FTP_WEIRD_227_FORMAT, 38 | ftp_cant_get_host = native::CURLE_FTP_CANT_GET_HOST, 39 | ftp_couldnt_set_type = native::CURLE_FTP_COULDNT_SET_TYPE, 40 | partial_file = native::CURLE_PARTIAL_FILE, 41 | ftp_couldnt_retr_file = native::CURLE_FTP_COULDNT_RETR_FILE, 42 | quote_error = native::CURLE_QUOTE_ERROR, 43 | http_returned_error = native::CURLE_HTTP_RETURNED_ERROR, 44 | write_error = native::CURLE_WRITE_ERROR, 45 | upload_failed = native::CURLE_UPLOAD_FAILED, 46 | read_error = native::CURLE_READ_ERROR, 47 | out_of_memory = native::CURLE_OUT_OF_MEMORY, 48 | operation_timedout = native::CURLE_OPERATION_TIMEDOUT, 49 | ftp_port_failed = native::CURLE_FTP_PORT_FAILED, 50 | ftp_couldnt_use_rest = native::CURLE_FTP_COULDNT_USE_REST, 51 | range_error = native::CURLE_RANGE_ERROR, 52 | http_post_error = native::CURLE_HTTP_POST_ERROR, 53 | ssl_connect_error = native::CURLE_SSL_CONNECT_ERROR, 54 | bad_download_resume = native::CURLE_BAD_DOWNLOAD_RESUME, 55 | file_couldnt_read_file = native::CURLE_FILE_COULDNT_READ_FILE, 56 | ldap_cannot_bind = native::CURLE_LDAP_CANNOT_BIND, 57 | ldap_search_failed = native::CURLE_LDAP_SEARCH_FAILED, 58 | function_not_found = native::CURLE_FUNCTION_NOT_FOUND, 59 | aborted_by_callback = native::CURLE_ABORTED_BY_CALLBACK, 60 | bad_function_argument = native::CURLE_BAD_FUNCTION_ARGUMENT, 61 | interface_failed = native::CURLE_INTERFACE_FAILED, 62 | too_many_redirects = native::CURLE_TOO_MANY_REDIRECTS , 63 | unknown_option = native::CURLE_UNKNOWN_OPTION, 64 | telnet_option_syntax = native::CURLE_TELNET_OPTION_SYNTAX , 65 | peer_failed_verification = native::CURLE_PEER_FAILED_VERIFICATION, 66 | got_nothing = native::CURLE_GOT_NOTHING, 67 | ssl_engine_notfound = native::CURLE_SSL_ENGINE_NOTFOUND, 68 | ssl_engine_setfailed = native::CURLE_SSL_ENGINE_SETFAILED, 69 | send_error = native::CURLE_SEND_ERROR, 70 | recv_error = native::CURLE_RECV_ERROR, 71 | ssl_certproblem = native::CURLE_SSL_CERTPROBLEM, 72 | ssl_cipher = native::CURLE_SSL_CIPHER, 73 | ssl_cacert = native::CURLE_SSL_CACERT, 74 | bad_content_encoding = native::CURLE_BAD_CONTENT_ENCODING, 75 | ldap_invalid_url = native::CURLE_LDAP_INVALID_URL, 76 | filesize_exceeded = native::CURLE_FILESIZE_EXCEEDED, 77 | use_ssl_failed = native::CURLE_USE_SSL_FAILED, 78 | send_fail_rewind = native::CURLE_SEND_FAIL_REWIND, 79 | ssl_engine_initfailed = native::CURLE_SSL_ENGINE_INITFAILED, 80 | login_denied = native::CURLE_LOGIN_DENIED, 81 | tftp_notfound = native::CURLE_TFTP_NOTFOUND, 82 | tftp_perm = native::CURLE_TFTP_PERM, 83 | remote_disk_full = native::CURLE_REMOTE_DISK_FULL, 84 | tftp_illegal = native::CURLE_TFTP_ILLEGAL, 85 | tftp_unknownid = native::CURLE_TFTP_UNKNOWNID, 86 | remote_file_exists = native::CURLE_REMOTE_FILE_EXISTS, 87 | tftp_nosuchuser = native::CURLE_TFTP_NOSUCHUSER, 88 | conv_failed = native::CURLE_CONV_FAILED, 89 | conv_reqd = native::CURLE_CONV_REQD, 90 | ssl_cacert_badfile = native::CURLE_SSL_CACERT_BADFILE, 91 | remote_file_not_found = native::CURLE_REMOTE_FILE_NOT_FOUND, 92 | ssh = native::CURLE_SSH, 93 | ssl_shutdown_failed = native::CURLE_SSL_SHUTDOWN_FAILED, 94 | again = native::CURLE_AGAIN, 95 | ssl_crl_badfile = native::CURLE_SSL_CRL_BADFILE, 96 | ssl_issuer_error = native::CURLE_SSL_ISSUER_ERROR, 97 | ftp_pret_failed = native::CURLE_FTP_PRET_FAILED, 98 | rtsp_cseq_error = native::CURLE_RTSP_CSEQ_ERROR, 99 | rtsp_session_error = native::CURLE_RTSP_SESSION_ERROR, 100 | ftp_bad_file_list = native::CURLE_FTP_BAD_FILE_LIST, 101 | chunk_failed = native::CURLE_CHUNK_FAILED 102 | }; 103 | } 104 | 105 | namespace multi 106 | { 107 | enum multi_error_codes 108 | { 109 | success = native::CURLM_OK, 110 | bad_handle = native::CURLM_BAD_HANDLE, 111 | bad_easy_handle = native::CURLM_BAD_EASY_HANDLE, 112 | out_of_memory = native::CURLM_OUT_OF_MEMORY, 113 | intenral_error = native::CURLM_INTERNAL_ERROR, 114 | bad_socket = native::CURLM_BAD_SOCKET, 115 | unknown_option = native::CURLM_UNKNOWN_OPTION 116 | }; 117 | } 118 | 119 | namespace share 120 | { 121 | enum share_error_codes 122 | { 123 | success = native::CURLSHE_OK, 124 | bad_option = native::CURLSHE_BAD_OPTION, 125 | in_use = native::CURLSHE_IN_USE, 126 | invalid = native::CURLSHE_INVALID, 127 | nomem = native::CURLSHE_NOMEM, 128 | not_built_in = native::CURLSHE_NOT_BUILT_IN 129 | }; 130 | } 131 | 132 | namespace form 133 | { 134 | enum form_error_codes 135 | { 136 | success = native::CURL_FORMADD_OK, 137 | memory = native::CURL_FORMADD_MEMORY, 138 | option_twice = native::CURL_FORMADD_OPTION_TWICE, 139 | null = native::CURL_FORMADD_NULL, 140 | unknown_option = native::CURL_FORMADD_UNKNOWN_OPTION, 141 | incomplete = native::CURL_FORMADD_INCOMPLETE, 142 | illegal_array = native::CURL_FORMADD_ILLEGAL_ARRAY, 143 | disabled = native::CURL_FORMADD_DISABLED 144 | }; 145 | } 146 | 147 | const boost::system::error_category& get_easy_category() BOOST_NOEXCEPT; 148 | const boost::system::error_category& get_multi_category() BOOST_NOEXCEPT; 149 | const boost::system::error_category& get_share_category() BOOST_NOEXCEPT; 150 | const boost::system::error_category& get_form_category() BOOST_NOEXCEPT; 151 | } 152 | } 153 | 154 | namespace boost 155 | { 156 | namespace system 157 | { 158 | template<> struct is_error_code_enum 159 | { 160 | static const bool value = true; 161 | }; 162 | 163 | template<> struct is_error_code_enum 164 | { 165 | static const bool value = true; 166 | }; 167 | 168 | template<> struct is_error_code_enum 169 | { 170 | static const bool value = true; 171 | }; 172 | 173 | template<> struct is_error_code_enum 174 | { 175 | static const bool value = true; 176 | }; 177 | 178 | template<> struct is_error_code_enum 179 | { 180 | static const bool value = true; 181 | }; 182 | 183 | template<> struct is_error_code_enum 184 | { 185 | static const bool value = true; 186 | }; 187 | 188 | template<> struct is_error_code_enum 189 | { 190 | static const bool value = true; 191 | }; 192 | 193 | template<> struct is_error_code_enum 194 | { 195 | static const bool value = true; 196 | }; 197 | } 198 | } 199 | 200 | namespace curl 201 | { 202 | namespace errc 203 | { 204 | namespace easy 205 | { 206 | inline boost::system::error_code make_error_code(easy_error_codes e) 207 | { 208 | return boost::system::error_code(static_cast(e), get_easy_category()); 209 | } 210 | } 211 | 212 | namespace multi 213 | { 214 | inline boost::system::error_code make_error_code(multi_error_codes e) 215 | { 216 | return boost::system::error_code(static_cast(e), get_multi_category()); 217 | } 218 | } 219 | 220 | namespace share 221 | { 222 | inline boost::system::error_code make_error_code(share_error_codes e) 223 | { 224 | return boost::system::error_code(static_cast(e), get_share_category()); 225 | } 226 | } 227 | 228 | namespace form 229 | { 230 | inline boost::system::error_code make_error_code(form_error_codes e) 231 | { 232 | return boost::system::error_code(static_cast(e), get_form_category()); 233 | } 234 | } 235 | } 236 | 237 | namespace native 238 | { 239 | inline boost::system::error_code make_error_code(CURLcode e) 240 | { 241 | return make_error_code(static_cast(e)); 242 | } 243 | 244 | inline boost::system::error_code make_error_code(CURLMcode e) 245 | { 246 | return make_error_code(static_cast(e)); 247 | } 248 | 249 | inline boost::system::error_code make_error_code(CURLSHcode e) 250 | { 251 | return make_error_code(static_cast(e)); 252 | } 253 | 254 | inline boost::system::error_code make_error_code(CURLFORMcode e) 255 | { 256 | return make_error_code(static_cast(e)); 257 | } 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /src/multi.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | Integration of libcurl's multi interface with Boost.Asio 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace curl; 15 | 16 | multi::multi(boost::asio::io_service& io_service): 17 | io_service_(io_service), 18 | timeout_(io_service), 19 | still_running_(0) 20 | { 21 | initref_ = initialization::ensure_initialization(); 22 | handle_ = native::curl_multi_init(); 23 | 24 | if (!handle_) 25 | { 26 | throw std::bad_alloc(); 27 | } 28 | 29 | set_socket_function(&multi::socket); 30 | set_socket_data(this); 31 | 32 | set_timer_function(&multi::timer); 33 | set_timer_data(this); 34 | } 35 | 36 | multi::~multi() 37 | { 38 | while (!easy_handles_.empty()) 39 | { 40 | easy_set_type::iterator it = easy_handles_.begin(); 41 | easy* easy_handle = *it; 42 | easy_handle->cancel(); 43 | } 44 | 45 | if (handle_) 46 | { 47 | native::curl_multi_cleanup(handle_); 48 | handle_ = 0; 49 | } 50 | } 51 | 52 | void multi::add(easy* easy_handle) 53 | { 54 | easy_handles_.insert(easy_handle); 55 | add_handle(easy_handle->native_handle()); 56 | } 57 | 58 | void multi::remove(easy* easy_handle) 59 | { 60 | easy_set_type::iterator it = easy_handles_.find(easy_handle); 61 | 62 | if (it != easy_handles_.end()) 63 | { 64 | easy_handles_.erase(it); 65 | remove_handle(easy_handle->native_handle()); 66 | } 67 | } 68 | 69 | void multi::socket_register(boost::shared_ptr si) 70 | { 71 | socket_type::native_handle_type fd = si->socket->native_handle(); 72 | sockets_.insert(socket_map_type::value_type(fd, si)); 73 | } 74 | 75 | void multi::socket_cleanup(native::curl_socket_t s) 76 | { 77 | socket_map_type::iterator it = sockets_.find(s); 78 | 79 | if (it != sockets_.end()) 80 | { 81 | socket_info_ptr p = it->second; 82 | monitor_socket(p, CURL_POLL_NONE); 83 | p->socket.reset(); 84 | sockets_.erase(it); 85 | } 86 | } 87 | 88 | void multi::add_handle(native::CURL* native_easy) 89 | { 90 | boost::system::error_code ec(native::curl_multi_add_handle(handle_, native_easy)); 91 | boost::asio::detail::throw_error(ec, "add_handle"); 92 | } 93 | 94 | void multi::remove_handle(native::CURL* native_easy) 95 | { 96 | boost::system::error_code ec(native::curl_multi_remove_handle(handle_, native_easy)); 97 | boost::asio::detail::throw_error(ec, "remove_handle"); 98 | } 99 | 100 | void multi::assign(native::curl_socket_t sockfd, void* user_data) 101 | { 102 | boost::system::error_code ec(native::curl_multi_assign(handle_, sockfd, user_data)); 103 | boost::asio::detail::throw_error(ec, "multi_assign"); 104 | } 105 | 106 | void multi::socket_action(native::curl_socket_t s, int event_bitmask) 107 | { 108 | boost::system::error_code ec(native::curl_multi_socket_action(handle_, s, event_bitmask, &still_running_)); 109 | boost::asio::detail::throw_error(ec); 110 | 111 | if (!still_running()) 112 | { 113 | timeout_.cancel(); 114 | } 115 | } 116 | 117 | void multi::set_socket_function(socket_function_t socket_function) 118 | { 119 | boost::system::error_code ec(native::curl_multi_setopt(handle_, native::CURLMOPT_SOCKETFUNCTION, socket_function)); 120 | boost::asio::detail::throw_error(ec, "set_socket_function"); 121 | } 122 | 123 | void multi::set_socket_data(void* socket_data) 124 | { 125 | boost::system::error_code ec(native::curl_multi_setopt(handle_, native::CURLMOPT_SOCKETDATA, socket_data)); 126 | boost::asio::detail::throw_error(ec, "set_socket_data"); 127 | } 128 | 129 | void multi::set_timer_function(timer_function_t timer_function) 130 | { 131 | boost::system::error_code ec(native::curl_multi_setopt(handle_, native::CURLMOPT_TIMERFUNCTION, timer_function)); 132 | boost::asio::detail::throw_error(ec, "set_timer_function"); 133 | } 134 | 135 | void multi::set_timer_data(void* timer_data) 136 | { 137 | boost::system::error_code ec(native::curl_multi_setopt(handle_, native::CURLMOPT_TIMERDATA, timer_data)); 138 | boost::asio::detail::throw_error(ec, "set_timer_data"); 139 | } 140 | 141 | void multi::monitor_socket(socket_info_ptr si, int action) 142 | { 143 | si->monitor_read = !!(action & CURL_POLL_IN); 144 | si->monitor_write = !!(action & CURL_POLL_OUT); 145 | 146 | if (!si->socket) 147 | { 148 | // If libcurl already requested destruction of the socket, then no further action is required. 149 | return; 150 | } 151 | 152 | if (si->monitor_read && !si->pending_read_op) 153 | { 154 | start_read_op(si); 155 | } 156 | 157 | if (si->monitor_write && !si->pending_write_op) 158 | { 159 | start_write_op(si); 160 | } 161 | 162 | // The CancelIoEx API is only available on Windows Vista and up. On Windows XP, the cancel operation therefore falls 163 | // back to CancelIo(), which only works in single-threaded environments and depends on driver support, which is not always available. 164 | // Therefore, this code section is only enabled when explicitly targeting Windows Vista and up or a non-Windows platform. 165 | // On Windows XP and previous versions, the I/O handler will be executed and immediately return. 166 | #if !defined(BOOST_WINDOWS_API) || (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600)) 167 | if (action == CURL_POLL_NONE && (si->pending_read_op || si->pending_write_op)) 168 | { 169 | si->socket->cancel(); 170 | } 171 | #endif 172 | } 173 | 174 | void multi::process_messages() 175 | { 176 | native::CURLMsg* msg; 177 | int msgs_left; 178 | 179 | while ((msg = native::curl_multi_info_read(handle_, &msgs_left))) 180 | { 181 | if (msg->msg == native::CURLMSG_DONE) 182 | { 183 | easy* easy_handle = easy::from_native(msg->easy_handle); 184 | boost::system::error_code ec; 185 | 186 | if (msg->data.result != native::CURLE_OK) 187 | { 188 | ec = boost::system::error_code(msg->data.result); 189 | } 190 | 191 | remove(easy_handle); 192 | easy_handle->handle_completion(ec); 193 | } 194 | } 195 | } 196 | 197 | bool multi::still_running() 198 | { 199 | return (still_running_ > 0); 200 | } 201 | 202 | void multi::start_read_op(socket_info_ptr si) 203 | { 204 | si->pending_read_op = true; 205 | si->socket->async_read_some(boost::asio::null_buffers(), boost::bind(&multi::handle_socket_read, this, boost::asio::placeholders::error, si)); 206 | } 207 | 208 | void multi::handle_socket_read(const boost::system::error_code& err, socket_info_ptr si) 209 | { 210 | if (!si->socket) 211 | { 212 | si->pending_read_op = false; 213 | return; 214 | } 215 | 216 | if (!err) 217 | { 218 | socket_action(si->socket->native_handle(), CURL_CSELECT_IN); 219 | process_messages(); 220 | 221 | if (si->monitor_read) 222 | start_read_op(si); 223 | else 224 | si->pending_read_op = false; 225 | } 226 | else 227 | { 228 | if (err != boost::asio::error::operation_aborted) 229 | { 230 | socket_action(si->socket->native_handle(), CURL_CSELECT_ERR); 231 | process_messages(); 232 | } 233 | 234 | si->pending_read_op = false; 235 | } 236 | } 237 | 238 | void multi::start_write_op(socket_info_ptr si) 239 | { 240 | si->pending_write_op = true; 241 | si->socket->async_write_some(boost::asio::null_buffers(), boost::bind(&multi::handle_socket_write, this, boost::asio::placeholders::error, si)); 242 | } 243 | 244 | void multi::handle_socket_write(const boost::system::error_code& err, socket_info_ptr si) 245 | { 246 | if (!si->socket) 247 | { 248 | si->pending_write_op = false; 249 | return; 250 | } 251 | 252 | if (!err) 253 | { 254 | socket_action(si->socket->native_handle(), CURL_CSELECT_OUT); 255 | process_messages(); 256 | 257 | if (si->monitor_write) 258 | start_write_op(si); 259 | else 260 | si->pending_write_op = false; 261 | } 262 | else 263 | { 264 | if (err != boost::asio::error::operation_aborted) 265 | { 266 | socket_action(si->socket->native_handle(), CURL_CSELECT_ERR); 267 | process_messages(); 268 | } 269 | 270 | si->pending_write_op = false; 271 | } 272 | } 273 | 274 | void multi::handle_timeout(const boost::system::error_code& err) 275 | { 276 | if (!err) 277 | { 278 | socket_action(CURL_SOCKET_TIMEOUT, 0); 279 | process_messages(); 280 | } 281 | } 282 | 283 | multi::socket_info_ptr multi::get_socket_from_native(native::curl_socket_t native_socket) 284 | { 285 | socket_map_type::iterator it = sockets_.find(native_socket); 286 | 287 | if (it != sockets_.end()) 288 | { 289 | return it->second; 290 | } 291 | else 292 | { 293 | return socket_info_ptr(); 294 | } 295 | } 296 | 297 | int multi::socket(native::CURL* native_easy, native::curl_socket_t s, int what, void* userp, void* socketp) 298 | { 299 | multi* self = static_cast(userp); 300 | 301 | if (what == CURL_POLL_REMOVE) 302 | { 303 | // stop listening for events 304 | socket_info_ptr* si = static_cast(socketp); 305 | self->monitor_socket(*si, CURL_POLL_NONE); 306 | delete si; 307 | } 308 | else if (socketp) 309 | { 310 | // change direction 311 | socket_info_ptr* si = static_cast(socketp); 312 | (*si)->handle = easy::from_native(native_easy); 313 | self->monitor_socket(*si, what); 314 | } 315 | else if (native_easy) 316 | { 317 | // register the socket 318 | socket_info_ptr si = self->get_socket_from_native(s); 319 | if (!si) 320 | throw std::invalid_argument("bad socket"); 321 | si->handle = easy::from_native(native_easy); 322 | self->assign(s, new socket_info_ptr(si)); 323 | self->monitor_socket(si, what); 324 | } 325 | else 326 | { 327 | throw std::invalid_argument("neither socketp nor native_easy were set"); 328 | } 329 | 330 | return 0; 331 | } 332 | 333 | int multi::timer(native::CURLM* native_multi, long timeout_ms, void* userp) 334 | { 335 | multi* self = static_cast(userp); 336 | 337 | if (timeout_ms > 0) 338 | { 339 | self->timeout_.expires_from_now(boost::posix_time::millisec(timeout_ms)); 340 | self->timeout_.async_wait(boost::bind(&multi::handle_timeout, self, boost::asio::placeholders::error)); 341 | } 342 | else 343 | { 344 | self->timeout_.cancel(); 345 | self->handle_timeout(boost::system::error_code()); 346 | } 347 | 348 | return 0; 349 | } 350 | -------------------------------------------------------------------------------- /src/easy.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for libcurl's easy interface 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace curl; 18 | 19 | easy* easy::from_native(native::CURL* native_easy) 20 | { 21 | easy* easy_handle; 22 | native::curl_easy_getinfo(native_easy, native::CURLINFO_PRIVATE, &easy_handle); 23 | return easy_handle; 24 | } 25 | 26 | easy::easy(boost::asio::io_service& io_service): 27 | io_service_(io_service), 28 | multi_(0), 29 | multi_registered_(false) 30 | { 31 | init(); 32 | } 33 | 34 | easy::easy(multi& multi_handle): 35 | io_service_(multi_handle.get_io_service()), 36 | multi_(&multi_handle), 37 | multi_registered_(false) 38 | { 39 | init(); 40 | } 41 | 42 | easy::~easy() 43 | { 44 | cancel(); 45 | 46 | if (handle_) 47 | { 48 | native::curl_easy_cleanup(handle_); 49 | handle_ = 0; 50 | } 51 | } 52 | 53 | void easy::perform() 54 | { 55 | boost::system::error_code ec; 56 | perform(ec); 57 | boost::asio::detail::throw_error(ec, "perform"); 58 | } 59 | 60 | void easy::perform(boost::system::error_code& ec) 61 | { 62 | if (multi_) 63 | { 64 | throw std::runtime_error("attempt to perform synchronous operation while being attached to a multi object"); 65 | } 66 | 67 | ec = boost::system::error_code(native::curl_easy_perform(handle_)); 68 | 69 | if (sink_) 70 | { 71 | sink_->flush(); 72 | } 73 | } 74 | 75 | void easy::async_perform(handler_type handler) 76 | { 77 | if (!multi_) 78 | { 79 | throw std::runtime_error("attempt to perform async. operation without assigning a multi object"); 80 | } 81 | 82 | // Cancel all previous async. operations 83 | cancel(); 84 | 85 | // Keep track of all new sockets 86 | set_opensocket_function(&easy::opensocket); 87 | set_opensocket_data(this); 88 | 89 | // This one is tricky: Although sockets are opened in the context of an easy object, they can outlive the easy objects and be transferred into a multi object's connection pool. Why there is no connection pool interface in the multi interface to plug into to begin with is still a mystery to me. Either way, the close events have to be tracked by the multi object as sockets are usually closed when curl_multi_cleanup is invoked. 90 | set_closesocket_function(&easy::closesocket); 91 | set_closesocket_data(multi_); 92 | 93 | handler_ = handler; 94 | multi_registered_ = true; 95 | 96 | // Registering the easy handle with the multi handle might invoke a set of callbacks right away which cause the completion event to fire from within this function. 97 | multi_->add(this); 98 | } 99 | 100 | void easy::cancel() 101 | { 102 | if (multi_registered_) 103 | { 104 | handle_completion(boost::system::error_code(boost::asio::error::operation_aborted)); 105 | multi_->remove(this); 106 | } 107 | } 108 | 109 | void easy::set_source(boost::shared_ptr source) 110 | { 111 | boost::system::error_code ec; 112 | set_source(source, ec); 113 | boost::asio::detail::throw_error(ec, "set_source"); 114 | } 115 | 116 | void easy::set_source(boost::shared_ptr source, boost::system::error_code& ec) 117 | { 118 | source_ = source; 119 | set_read_function(&easy::read_function, ec); 120 | if (!ec) set_read_data(this, ec); 121 | if (!ec) set_seek_function(&easy::seek_function, ec); 122 | if (!ec) set_seek_data(this, ec); 123 | } 124 | 125 | void easy::set_sink(boost::shared_ptr sink) 126 | { 127 | boost::system::error_code ec; 128 | set_sink(sink, ec); 129 | boost::asio::detail::throw_error(ec, "set_sink"); 130 | } 131 | 132 | void easy::set_sink(boost::shared_ptr sink, boost::system::error_code& ec) 133 | { 134 | sink_ = sink; 135 | set_write_function(&easy::write_function); 136 | if (!ec) set_write_data(this); 137 | } 138 | 139 | void easy::unset_progress_callback() 140 | { 141 | set_no_progress(true); 142 | #if LIBCURL_VERSION_NUM < 0x072000 143 | set_progress_function(0); 144 | set_progress_data(0); 145 | #else 146 | set_xferinfo_function(0); 147 | set_xferinfo_data(0); 148 | #endif 149 | } 150 | 151 | void easy::set_progress_callback(progress_callback_t progress_callback) 152 | { 153 | progress_callback_ = progress_callback; 154 | set_no_progress(false); 155 | #if LIBCURL_VERSION_NUM < 0x072000 156 | set_progress_function(&easy::progress_function); 157 | set_progress_data(this); 158 | #else 159 | set_xferinfo_function(&easy::xferinfo_function); 160 | set_xferinfo_data(this); 161 | #endif 162 | } 163 | 164 | void easy::set_post_fields(const std::string& post_fields) 165 | { 166 | boost::system::error_code ec; 167 | set_post_fields(post_fields, ec); 168 | boost::asio::detail::throw_error(ec, "set_post_fields"); 169 | } 170 | 171 | void easy::set_post_fields(const std::string& post_fields, boost::system::error_code& ec) 172 | { 173 | post_fields_ = post_fields; 174 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_POSTFIELDS, post_fields_.c_str())); 175 | 176 | if (!ec) 177 | set_post_field_size_large(static_cast(post_fields_.length()), ec); 178 | } 179 | 180 | void easy::set_http_post(boost::shared_ptr form) 181 | { 182 | boost::system::error_code ec; 183 | set_http_post(form, ec); 184 | boost::asio::detail::throw_error(ec, "set_http_post"); 185 | } 186 | 187 | void easy::set_http_post(boost::shared_ptr form, boost::system::error_code& ec) 188 | { 189 | form_ = form; 190 | 191 | if (form_) 192 | { 193 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPPOST, form_->native_handle())); 194 | } 195 | else 196 | { 197 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPPOST, NULL)); 198 | } 199 | } 200 | 201 | void easy::add_header(const std::string& name, const std::string& value) 202 | { 203 | boost::system::error_code ec; 204 | add_header(name, value, ec); 205 | boost::asio::detail::throw_error(ec, "add_header"); 206 | } 207 | 208 | void easy::add_header(const std::string& name, const std::string& value, boost::system::error_code& ec) 209 | { 210 | add_header(name + ": " + value, ec); 211 | } 212 | 213 | void easy::add_header(const std::string& header) 214 | { 215 | boost::system::error_code ec; 216 | add_header(header, ec); 217 | boost::asio::detail::throw_error(ec, "add_header"); 218 | } 219 | 220 | void easy::add_header(const std::string& header, boost::system::error_code& ec) 221 | { 222 | if (!headers_) 223 | { 224 | headers_ = boost::make_shared(); 225 | } 226 | 227 | headers_->add(header); 228 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle())); 229 | } 230 | 231 | void easy::set_headers(boost::shared_ptr headers) 232 | { 233 | boost::system::error_code ec; 234 | set_headers(headers, ec); 235 | boost::asio::detail::throw_error(ec, "set_headers"); 236 | } 237 | 238 | void easy::set_headers(boost::shared_ptr headers, boost::system::error_code& ec) 239 | { 240 | headers_ = headers; 241 | 242 | if (headers_) 243 | { 244 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, headers_->native_handle())); 245 | } 246 | else 247 | { 248 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPHEADER, NULL)); 249 | } 250 | } 251 | 252 | void easy::add_http200_alias(const std::string& http200_alias) 253 | { 254 | boost::system::error_code ec; 255 | add_http200_alias(http200_alias, ec); 256 | boost::asio::detail::throw_error(ec, "add_http200_alias"); 257 | } 258 | 259 | void easy::add_http200_alias(const std::string& http200_alias, boost::system::error_code& ec) 260 | { 261 | if (!http200_aliases_) 262 | { 263 | http200_aliases_ = boost::make_shared(); 264 | } 265 | 266 | http200_aliases_->add(http200_alias); 267 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases_->native_handle())); 268 | } 269 | 270 | void easy::set_http200_aliases(boost::shared_ptr http200_aliases) 271 | { 272 | boost::system::error_code ec; 273 | set_http200_aliases(http200_aliases, ec); 274 | boost::asio::detail::throw_error(ec, "set_http200_aliases"); 275 | } 276 | 277 | void easy::set_http200_aliases(boost::shared_ptr http200_aliases, boost::system::error_code& ec) 278 | { 279 | http200_aliases_ = http200_aliases; 280 | 281 | if (http200_aliases) 282 | { 283 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, http200_aliases->native_handle())); 284 | } 285 | else 286 | { 287 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTP200ALIASES, NULL)); 288 | } 289 | } 290 | 291 | void easy::add_mail_rcpt(const std::string& mail_rcpt) 292 | { 293 | boost::system::error_code ec; 294 | add_mail_rcpt(mail_rcpt, ec); 295 | boost::asio::detail::throw_error(ec, "add_mail_rcpt"); 296 | } 297 | 298 | void easy::add_mail_rcpt(const std::string& mail_rcpt, boost::system::error_code& ec) 299 | { 300 | if (!mail_rcpts_) 301 | { 302 | mail_rcpts_ = boost::make_shared(); 303 | } 304 | 305 | mail_rcpts_->add(mail_rcpt); 306 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_MAIL_RCPT, mail_rcpts_->native_handle())); 307 | } 308 | 309 | void easy::set_mail_rcpts(boost::shared_ptr mail_rcpts) 310 | { 311 | boost::system::error_code ec; 312 | set_mail_rcpts(mail_rcpts, ec); 313 | boost::asio::detail::throw_error(ec, "set_mail_rcpts"); 314 | } 315 | 316 | void easy::set_mail_rcpts(boost::shared_ptr mail_rcpts, boost::system::error_code& ec) 317 | { 318 | mail_rcpts_ = mail_rcpts; 319 | 320 | if (mail_rcpts_) 321 | { 322 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_MAIL_RCPT, mail_rcpts_->native_handle())); 323 | } 324 | else 325 | { 326 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_MAIL_RCPT, NULL)); 327 | } 328 | } 329 | 330 | void easy::add_quote(const std::string& quote) 331 | { 332 | boost::system::error_code ec; 333 | add_quote(quote, ec); 334 | boost::asio::detail::throw_error(ec, "add_quote"); 335 | } 336 | 337 | void easy::add_quote(const std::string& quote, boost::system::error_code& ec) 338 | { 339 | if (!quotes_) 340 | { 341 | quotes_ = boost::make_shared(); 342 | } 343 | 344 | quotes_->add(quote); 345 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_QUOTE, quotes_->native_handle())); 346 | } 347 | 348 | void easy::set_quotes(boost::shared_ptr quotes) 349 | { 350 | boost::system::error_code ec; 351 | set_quotes(quotes, ec); 352 | boost::asio::detail::throw_error(ec, "set_quotes"); 353 | } 354 | 355 | void easy::set_quotes(boost::shared_ptr quotes, boost::system::error_code& ec) 356 | { 357 | quotes_ = quotes; 358 | 359 | if (mail_rcpts_) 360 | { 361 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_QUOTE, quotes_->native_handle())); 362 | } 363 | else 364 | { 365 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_QUOTE, NULL)); 366 | } 367 | } 368 | 369 | void easy::add_resolve(const std::string& resolved_host) 370 | { 371 | boost::system::error_code ec; 372 | add_resolve(resolved_host, ec); 373 | boost::asio::detail::throw_error(ec, "add_resolve"); 374 | } 375 | 376 | void easy::add_resolve(const std::string& resolved_host, boost::system::error_code& ec) 377 | { 378 | if (!resolved_hosts_) 379 | { 380 | resolved_hosts_ = boost::make_shared(); 381 | } 382 | 383 | resolved_hosts_->add(resolved_host); 384 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle())); 385 | } 386 | 387 | void easy::set_resolves(boost::shared_ptr resolved_hosts) 388 | { 389 | boost::system::error_code ec; 390 | set_resolves(resolved_hosts, ec); 391 | boost::asio::detail::throw_error(ec, "set_resolves"); 392 | } 393 | 394 | void easy::set_resolves(boost::shared_ptr resolved_hosts, boost::system::error_code& ec) 395 | { 396 | resolved_hosts_ = resolved_hosts; 397 | 398 | if (resolved_hosts_) 399 | { 400 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, resolved_hosts_->native_handle())); 401 | } 402 | else 403 | { 404 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_RESOLVE, NULL)); 405 | } 406 | } 407 | 408 | void easy::set_share(boost::shared_ptr share) 409 | { 410 | boost::system::error_code ec; 411 | set_share(share, ec); 412 | boost::asio::detail::throw_error(ec, "set_share"); 413 | } 414 | 415 | void easy::set_share(boost::shared_ptr share, boost::system::error_code& ec) 416 | { 417 | share_ = share; 418 | 419 | if (share) 420 | { 421 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_SHARE, share->native_handle())); 422 | } 423 | else 424 | { 425 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_SHARE, NULL)); 426 | } 427 | } 428 | 429 | void easy::add_telnet_option(const std::string& telnet_option) 430 | { 431 | boost::system::error_code ec; 432 | add_telnet_option(telnet_option, ec); 433 | boost::asio::detail::throw_error(ec, "add_telnet_option"); 434 | } 435 | 436 | void easy::add_telnet_option(const std::string& telnet_option, boost::system::error_code& ec) 437 | { 438 | if (!telnet_options_) 439 | { 440 | telnet_options_ = boost::make_shared(); 441 | } 442 | 443 | telnet_options_->add(telnet_option); 444 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_TELNETOPTIONS, telnet_options_->native_handle())); 445 | } 446 | 447 | void easy::add_telnet_option(const std::string& option, const std::string& value) 448 | { 449 | boost::system::error_code ec; 450 | add_telnet_option(option, value, ec); 451 | boost::asio::detail::throw_error(ec, "add_telnet_option"); 452 | } 453 | 454 | void easy::add_telnet_option(const std::string& option, const std::string& value, boost::system::error_code& ec) 455 | { 456 | add_telnet_option(option + "=" + value, ec); 457 | } 458 | 459 | void easy::set_telnet_options(boost::shared_ptr telnet_options) 460 | { 461 | boost::system::error_code ec; 462 | set_telnet_options(telnet_options, ec); 463 | boost::asio::detail::throw_error(ec, "set_telnet_options"); 464 | } 465 | 466 | void easy::set_telnet_options(boost::shared_ptr telnet_options, boost::system::error_code& ec) 467 | { 468 | telnet_options_ = telnet_options; 469 | 470 | if (telnet_options_) 471 | { 472 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_TELNETOPTIONS, telnet_options_->native_handle())); 473 | } 474 | else 475 | { 476 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_TELNETOPTIONS, NULL)); 477 | } 478 | } 479 | 480 | void easy::handle_completion(const boost::system::error_code& err) 481 | { 482 | if (sink_) 483 | { 484 | sink_->flush(); 485 | } 486 | 487 | multi_registered_ = false; 488 | io_service_.post(boost::bind(handler_, err)); 489 | } 490 | 491 | void easy::init() 492 | { 493 | initref_ = initialization::ensure_initialization(); 494 | handle_ = native::curl_easy_init(); 495 | 496 | if (!handle_) 497 | { 498 | throw std::bad_alloc(); 499 | } 500 | 501 | set_private(this); 502 | } 503 | 504 | native::curl_socket_t easy::open_tcp_socket(native::curl_sockaddr* address) 505 | { 506 | boost::system::error_code ec; 507 | std::auto_ptr socket(new socket_type(io_service_)); 508 | 509 | switch (address->family) 510 | { 511 | case AF_INET: 512 | socket->open(boost::asio::ip::tcp::v4(), ec); 513 | break; 514 | 515 | case AF_INET6: 516 | socket->open(boost::asio::ip::tcp::v6(), ec); 517 | break; 518 | 519 | default: 520 | return CURL_SOCKET_BAD; 521 | } 522 | 523 | if (ec) 524 | { 525 | return CURL_SOCKET_BAD; 526 | } 527 | else 528 | { 529 | boost::shared_ptr si(new socket_info(this, socket)); 530 | multi_->socket_register(si); 531 | return si->socket->native_handle(); 532 | } 533 | } 534 | 535 | size_t easy::write_function(char* ptr, size_t size, size_t nmemb, void* userdata) 536 | { 537 | easy* self = static_cast(userdata); 538 | size_t actual_size = size * nmemb; 539 | 540 | if (!actual_size) 541 | { 542 | return 0; 543 | } 544 | 545 | if (!self->sink_->write(ptr, actual_size)) 546 | { 547 | return 0; 548 | } 549 | else 550 | { 551 | return actual_size; 552 | } 553 | } 554 | 555 | size_t easy::read_function(void* ptr, size_t size, size_t nmemb, void* userdata) 556 | { 557 | // FIXME readsome doesn't work with TFTP (see cURL docs) 558 | 559 | easy* self = static_cast(userdata); 560 | size_t actual_size = size * nmemb; 561 | 562 | if (self->source_->eof()) 563 | { 564 | return 0; 565 | } 566 | 567 | std::streamsize chars_stored = self->source_->readsome(static_cast(ptr), actual_size); 568 | 569 | if (!self->source_) 570 | { 571 | return CURL_READFUNC_ABORT; 572 | } 573 | else 574 | { 575 | return static_cast(chars_stored); 576 | } 577 | } 578 | 579 | int easy::seek_function(void* instream, native::curl_off_t offset, int origin) 580 | { 581 | // TODO we could allow the user to define an offset which this library should consider as position zero for uploading chunks of the file 582 | // alternatively do tellg() on the source stream when it is first passed to use_source() and use that as origin 583 | 584 | easy* self = static_cast(instream); 585 | 586 | std::ios::seekdir dir; 587 | 588 | switch (origin) 589 | { 590 | case SEEK_SET: 591 | dir = std::ios::beg; 592 | break; 593 | 594 | case SEEK_CUR: 595 | dir = std::ios::cur; 596 | break; 597 | 598 | case SEEK_END: 599 | dir = std::ios::end; 600 | break; 601 | 602 | default: 603 | return CURL_SEEKFUNC_FAIL; 604 | } 605 | 606 | if (!self->source_->seekg(offset, dir)) 607 | { 608 | return CURL_SEEKFUNC_FAIL; 609 | } 610 | else 611 | { 612 | return CURL_SEEKFUNC_OK; 613 | } 614 | } 615 | 616 | #if LIBCURL_VERSION_NUM < 0x072000 617 | int easy::progress_function(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow) 618 | { 619 | easy* self = static_cast(clientp); 620 | return self->progress_callback_( 621 | static_cast(dltotal), 622 | static_cast(dlnow), 623 | static_cast(ultotal), 624 | static_cast(ulnow) 625 | ) ? 0 : 1; 626 | } 627 | #else 628 | int easy::xferinfo_function(void* clientp, native::curl_off_t dltotal, native::curl_off_t dlnow, native::curl_off_t ultotal, native::curl_off_t ulnow) 629 | { 630 | easy* self = static_cast(clientp); 631 | return self->progress_callback_(dltotal, dlnow, ultotal, ulnow) ? 0 : 1; 632 | } 633 | #endif 634 | 635 | native::curl_socket_t easy::opensocket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address) 636 | { 637 | easy* self = static_cast(clientp); 638 | 639 | switch (purpose) 640 | { 641 | case native::CURLSOCKTYPE_IPCXN: 642 | switch (address->socktype) 643 | { 644 | case SOCK_STREAM: 645 | // Note to self: Why is address->protocol always set to zero? 646 | return self->open_tcp_socket(address); 647 | 648 | case SOCK_DGRAM: 649 | // TODO implement - I've seen other libcurl wrappers with UDP implementation, but have yet to read up on what this is used for 650 | return CURL_SOCKET_BAD; 651 | 652 | default: 653 | // unknown or invalid socket type 654 | return CURL_SOCKET_BAD; 655 | } 656 | break; 657 | 658 | #ifdef CURLSOCKTYPE_ACCEPT 659 | case native::CURLSOCKTYPE_ACCEPT: 660 | // TODO implement - is this used for active FTP? 661 | return CURL_SOCKET_BAD; 662 | #endif 663 | 664 | default: 665 | // unknown or invalid purpose 666 | return CURL_SOCKET_BAD; 667 | } 668 | } 669 | 670 | int easy::closesocket(void* clientp, native::curl_socket_t item) 671 | { 672 | multi* multi_handle = static_cast(clientp); 673 | multi_handle->socket_cleanup(item); 674 | return 0; 675 | } 676 | -------------------------------------------------------------------------------- /include/curl-asio/easy.h: -------------------------------------------------------------------------------- 1 | /** 2 | curl-asio: wrapper for integrating libcurl with boost.asio applications 3 | Copyright (c) 2013 Oliver Kuckertz 4 | See COPYING for license information. 5 | 6 | C++ wrapper for libcurl's easy interface 7 | */ 8 | 9 | #pragma once 10 | 11 | #include "config.h" 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "error_code.h" 22 | #include "initialization.h" 23 | 24 | #define IMPLEMENT_CURL_OPTION(FUNCTION_NAME, OPTION_NAME, OPTION_TYPE) \ 25 | inline void FUNCTION_NAME(OPTION_TYPE arg) \ 26 | { \ 27 | boost::system::error_code ec; \ 28 | FUNCTION_NAME(arg, ec); \ 29 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 30 | } \ 31 | inline void FUNCTION_NAME(OPTION_TYPE arg, boost::system::error_code& ec) \ 32 | { \ 33 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, OPTION_NAME, arg)); \ 34 | } 35 | 36 | #define IMPLEMENT_CURL_OPTION_BOOLEAN(FUNCTION_NAME, OPTION_NAME) \ 37 | inline void FUNCTION_NAME(bool enabled) \ 38 | { \ 39 | boost::system::error_code ec; \ 40 | FUNCTION_NAME(enabled, ec); \ 41 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 42 | } \ 43 | inline void FUNCTION_NAME(bool enabled, boost::system::error_code& ec) \ 44 | { \ 45 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, OPTION_NAME, enabled ? 1L : 0L)); \ 46 | } 47 | 48 | #define IMPLEMENT_CURL_OPTION_ENUM(FUNCTION_NAME, OPTION_NAME, ENUM_TYPE, OPTION_TYPE) \ 49 | inline void FUNCTION_NAME(ENUM_TYPE arg) \ 50 | { \ 51 | boost::system::error_code ec; \ 52 | FUNCTION_NAME(arg, ec); \ 53 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 54 | } \ 55 | inline void FUNCTION_NAME(ENUM_TYPE arg, boost::system::error_code& ec) \ 56 | { \ 57 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, OPTION_NAME, (OPTION_TYPE)arg)); \ 58 | } 59 | 60 | #define IMPLEMENT_CURL_OPTION_STRING(FUNCTION_NAME, OPTION_NAME) \ 61 | inline void FUNCTION_NAME(const char* str) \ 62 | { \ 63 | boost::system::error_code ec; \ 64 | FUNCTION_NAME(str, ec); \ 65 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 66 | } \ 67 | inline void FUNCTION_NAME(const char* str, boost::system::error_code& ec) \ 68 | { \ 69 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, OPTION_NAME, str)); \ 70 | } \ 71 | inline void FUNCTION_NAME(const std::string& str) \ 72 | { \ 73 | boost::system::error_code ec; \ 74 | FUNCTION_NAME(str, ec); \ 75 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 76 | } \ 77 | inline void FUNCTION_NAME(const std::string& str, boost::system::error_code& ec) \ 78 | { \ 79 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, OPTION_NAME, str.c_str())); \ 80 | } 81 | 82 | #define IMPLEMENT_CURL_OPTION_GET_STRING(FUNCTION_NAME, OPTION_NAME) \ 83 | inline std::string FUNCTION_NAME() \ 84 | { \ 85 | char *info = NULL; \ 86 | boost::system::error_code ec = boost::system::error_code(native::curl_easy_getinfo(handle_, OPTION_NAME, &info)); \ 87 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 88 | return info; \ 89 | } 90 | 91 | #define IMPLEMENT_CURL_OPTION_GET_DOUBLE(FUNCTION_NAME, OPTION_NAME) \ 92 | inline double FUNCTION_NAME() \ 93 | { \ 94 | double info; \ 95 | boost::system::error_code ec = boost::system::error_code(native::curl_easy_getinfo(handle_, OPTION_NAME, &info)); \ 96 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 97 | return info; \ 98 | } 99 | 100 | #define IMPLEMENT_CURL_OPTION_GET_LONG(FUNCTION_NAME, OPTION_NAME) \ 101 | inline long FUNCTION_NAME() \ 102 | { \ 103 | long info; \ 104 | boost::system::error_code ec = boost::system::error_code(native::curl_easy_getinfo(handle_, OPTION_NAME, &info)); \ 105 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 106 | return info; \ 107 | } 108 | 109 | #define IMPLEMENT_CURL_OPTION_GET_LIST(FUNCTION_NAME, OPTION_NAME) \ 110 | inline std::vector FUNCTION_NAME() \ 111 | { \ 112 | struct native::curl_slist *info; \ 113 | std::vector results; \ 114 | boost::system::error_code ec = boost::system::error_code(native::curl_easy_getinfo(handle_, OPTION_NAME, &info)); \ 115 | boost::asio::detail::throw_error(ec, BOOST_PP_STRINGIZE(FUNCTION_NAME)); \ 116 | struct native::curl_slist *it = info; \ 117 | while (it) \ 118 | { \ 119 | results.push_back(std::string(it->data)); \ 120 | it = it->next; \ 121 | } \ 122 | native::curl_slist_free_all(info); \ 123 | return results; \ 124 | } 125 | 126 | namespace curl 127 | { 128 | class form; 129 | class multi; 130 | class share; 131 | class string_list; 132 | 133 | class CURLASIO_API easy: 134 | public boost::noncopyable 135 | { 136 | public: 137 | typedef boost::function handler_type; 138 | 139 | static easy* from_native(native::CURL* native_easy); 140 | 141 | easy(boost::asio::io_service& io_service); 142 | easy(multi& multi_handle); 143 | ~easy(); 144 | 145 | inline native::CURL* native_handle() { return handle_; } 146 | 147 | void perform(); 148 | void perform(boost::system::error_code& ec); 149 | void async_perform(handler_type handler); 150 | void cancel(); 151 | void set_source(boost::shared_ptr source); 152 | void set_source(boost::shared_ptr source, boost::system::error_code& ec); 153 | void set_sink(boost::shared_ptr sink); 154 | void set_sink(boost::shared_ptr sink, boost::system::error_code& ec); 155 | 156 | typedef boost::function progress_callback_t; 157 | void unset_progress_callback(); 158 | void set_progress_callback(progress_callback_t progress_callback); 159 | 160 | // behavior options 161 | 162 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_verbose, native::CURLOPT_VERBOSE); 163 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_header, native::CURLOPT_HEADER); 164 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_progress, native::CURLOPT_NOPROGRESS); 165 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_signal, native::CURLOPT_NOSIGNAL); 166 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_wildcard_match, native::CURLOPT_WILDCARDMATCH); 167 | 168 | // callback options 169 | 170 | typedef size_t (*write_function_t)(char* ptr, size_t size, size_t nmemb, void* userdata); 171 | IMPLEMENT_CURL_OPTION(set_write_function, native::CURLOPT_WRITEFUNCTION, write_function_t); 172 | IMPLEMENT_CURL_OPTION(set_write_data, native::CURLOPT_WRITEDATA, void*); 173 | typedef size_t (*read_function_t)(void* ptr, size_t size, size_t nmemb, void* userdata); 174 | IMPLEMENT_CURL_OPTION(set_read_function, native::CURLOPT_READFUNCTION, read_function_t); 175 | IMPLEMENT_CURL_OPTION(set_read_data, native::CURLOPT_READDATA, void*); 176 | typedef native::curlioerr (*ioctl_function_t)(native::CURL* handle, int cmd, void* clientp); 177 | IMPLEMENT_CURL_OPTION(set_ioctl_function, native::CURLOPT_IOCTLFUNCTION, ioctl_function_t); 178 | IMPLEMENT_CURL_OPTION(set_ioctl_data, native::CURLOPT_IOCTLDATA, void*); 179 | typedef int (*seek_function_t)(void* instream, native::curl_off_t offset, int origin); 180 | IMPLEMENT_CURL_OPTION(set_seek_function, native::CURLOPT_SEEKFUNCTION, seek_function_t); 181 | IMPLEMENT_CURL_OPTION(set_seek_data, native::CURLOPT_SEEKDATA, void*); 182 | typedef int (*sockopt_function_t)(void* clientp, native::curl_socket_t curlfd, native::curlsocktype purpose); 183 | IMPLEMENT_CURL_OPTION(set_sockopt_function, native::CURLOPT_SOCKOPTFUNCTION, sockopt_function_t); 184 | IMPLEMENT_CURL_OPTION(set_sockopt_data, native::CURLOPT_SOCKOPTDATA, void*); 185 | typedef native::curl_socket_t (*opensocket_function_t)(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address); 186 | IMPLEMENT_CURL_OPTION(set_opensocket_function, native::CURLOPT_OPENSOCKETFUNCTION, opensocket_function_t); 187 | IMPLEMENT_CURL_OPTION(set_opensocket_data, native::CURLOPT_OPENSOCKETDATA, void*); 188 | typedef int (*closesocket_function_t)(void* clientp, native::curl_socket_t item); 189 | IMPLEMENT_CURL_OPTION(set_closesocket_function, native::CURLOPT_CLOSESOCKETFUNCTION, closesocket_function_t); 190 | IMPLEMENT_CURL_OPTION(set_closesocket_data, native::CURLOPT_CLOSESOCKETDATA, void*); 191 | typedef int (*progress_function_t)(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow); 192 | IMPLEMENT_CURL_OPTION(set_progress_function, native::CURLOPT_PROGRESSFUNCTION, progress_function_t); 193 | IMPLEMENT_CURL_OPTION(set_progress_data, native::CURLOPT_PROGRESSDATA, void*); 194 | #if LIBCURL_VERSION_NUM >= 0x072000 195 | typedef int (*xferinfo_function_t)(void* clientp, native::curl_off_t dltotal, native::curl_off_t dlnow, native::curl_off_t ultotal, native::curl_off_t ulnow); 196 | IMPLEMENT_CURL_OPTION(set_xferinfo_function, native::CURLOPT_XFERINFOFUNCTION, xferinfo_function_t); 197 | IMPLEMENT_CURL_OPTION(set_xferinfo_data, native::CURLOPT_XFERINFODATA, void*); 198 | #endif 199 | typedef size_t (*header_function_t)(void* ptr, size_t size, size_t nmemb, void* userdata); 200 | IMPLEMENT_CURL_OPTION(set_header_function, native::CURLOPT_HEADERFUNCTION, header_function_t); 201 | IMPLEMENT_CURL_OPTION(set_header_data, native::CURLOPT_HEADERDATA, void*); 202 | typedef int (*debug_callback_t)(native::CURL*, native::curl_infotype, char*, size_t, void*); 203 | IMPLEMENT_CURL_OPTION(set_debug_callback, native::CURLOPT_DEBUGFUNCTION, debug_callback_t); 204 | IMPLEMENT_CURL_OPTION(set_debug_data, native::CURLOPT_DEBUGDATA, void*); 205 | typedef native::CURLcode (*ssl_ctx_function_t)(native::CURL* curl, void* sslctx, void* parm); 206 | IMPLEMENT_CURL_OPTION(set_ssl_ctx_function, native::CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_function_t); 207 | IMPLEMENT_CURL_OPTION(set_ssl_ctx_data, native::CURLOPT_SSL_CTX_DATA, void*); 208 | typedef size_t (*interleave_function_t)(void* ptr, size_t size, size_t nmemb, void* userdata); 209 | IMPLEMENT_CURL_OPTION(set_interleave_function, native::CURLOPT_INTERLEAVEFUNCTION, interleave_function_t); 210 | IMPLEMENT_CURL_OPTION(set_interleave_data, native::CURLOPT_INTERLEAVEDATA, void*); 211 | 212 | // error options 213 | 214 | IMPLEMENT_CURL_OPTION(set_error_buffer, native::CURLOPT_ERRORBUFFER, char*); 215 | IMPLEMENT_CURL_OPTION(set_stderr, native::CURLOPT_STDERR, FILE*); 216 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_fail_on_error, native::CURLOPT_FAILONERROR); 217 | 218 | // network options 219 | 220 | IMPLEMENT_CURL_OPTION_STRING(set_url, native::CURLOPT_URL); 221 | IMPLEMENT_CURL_OPTION(set_protocols, native::CURLOPT_PROTOCOLS, long); 222 | IMPLEMENT_CURL_OPTION(set_redir_protocols, native::CURLOPT_REDIR_PROTOCOLS, long); 223 | IMPLEMENT_CURL_OPTION_STRING(set_proxy, native::CURLOPT_PROXY); 224 | IMPLEMENT_CURL_OPTION(set_proxy_port, native::CURLOPT_PROXYPORT, long); 225 | IMPLEMENT_CURL_OPTION(set_proxy_type, native::CURLOPT_PROXYTYPE, long); 226 | IMPLEMENT_CURL_OPTION_STRING(set_no_proxy, native::CURLOPT_NOPROXY); 227 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_proxy_tunnel, native::CURLOPT_HTTPPROXYTUNNEL); 228 | IMPLEMENT_CURL_OPTION_STRING(set_socks5_gsapi_service, native::CURLOPT_SOCKS5_GSSAPI_SERVICE); 229 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_socks5_gsapi_nec, native::CURLOPT_SOCKS5_GSSAPI_NEC); 230 | IMPLEMENT_CURL_OPTION_STRING(set_interface, native::CURLOPT_INTERFACE); 231 | IMPLEMENT_CURL_OPTION(set_local_port, native::CURLOPT_LOCALPORT, long); 232 | IMPLEMENT_CURL_OPTION(set_local_port_range, native::CURLOPT_LOCALPORTRANGE, long); 233 | IMPLEMENT_CURL_OPTION(set_dns_cache_timeout, native::CURLOPT_DNS_CACHE_TIMEOUT, long); 234 | IMPLEMENT_CURL_OPTION(set_buffer_size, native::CURLOPT_BUFFERSIZE, long); 235 | IMPLEMENT_CURL_OPTION(set_port, native::CURLOPT_PORT, long); 236 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_tcp_no_delay, native::CURLOPT_TCP_NODELAY); 237 | IMPLEMENT_CURL_OPTION(set_address_scope, native::CURLOPT_ADDRESS_SCOPE, long); 238 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_tcp_keep_alive, native::CURLOPT_TCP_KEEPALIVE); 239 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_tcp_keep_idle, native::CURLOPT_TCP_KEEPIDLE); 240 | IMPLEMENT_CURL_OPTION(set_tcp_keep_intvl, native::CURLOPT_TCP_KEEPINTVL, long); 241 | 242 | // authentication options 243 | 244 | enum netrc_t { netrc_optional = native::CURL_NETRC_OPTIONAL, netrc_ignored = native::CURL_NETRC_IGNORED, netrc_required = native::CURL_NETRC_REQUIRED }; 245 | IMPLEMENT_CURL_OPTION_ENUM(set_netrc, native::CURLOPT_NETRC, netrc_t, long); 246 | IMPLEMENT_CURL_OPTION_STRING(set_netrc_file, native::CURLOPT_NETRC_FILE); 247 | IMPLEMENT_CURL_OPTION_STRING(set_user, native::CURLOPT_USERNAME); 248 | IMPLEMENT_CURL_OPTION_STRING(set_password, native::CURLOPT_PASSWORD); 249 | IMPLEMENT_CURL_OPTION_STRING(set_proxy_user, native::CURLOPT_PROXYUSERNAME); 250 | IMPLEMENT_CURL_OPTION_STRING(set_proxy_password, native::CURLOPT_PROXYPASSWORD); 251 | enum httpauth_t { auth_basic = CURLAUTH_BASIC, auth_digest, auth_digest_ie, auth_gss_negotiate, auth_ntml, auth_nhtml_wb, auth_any, auth_any_safe }; 252 | inline void set_http_auth(httpauth_t auth, bool auth_only) 253 | { 254 | boost::system::error_code ec; 255 | set_http_auth(auth, auth_only, ec); 256 | boost::asio::detail::throw_error(ec, "set_http_auth"); 257 | } 258 | inline void set_http_auth(httpauth_t auth, bool auth_only, boost::system::error_code& ec) 259 | { 260 | long l = ((long)auth | (auth_only ? CURLAUTH_ONLY : 0L)); 261 | ec = boost::system::error_code(native::curl_easy_setopt(handle_, native::CURLOPT_HTTPAUTH, l)); 262 | } 263 | IMPLEMENT_CURL_OPTION(set_tls_auth_type, native::CURLOPT_TLSAUTH_TYPE, long); 264 | IMPLEMENT_CURL_OPTION_STRING(set_tls_auth_user, native::CURLOPT_TLSAUTH_USERNAME); 265 | IMPLEMENT_CURL_OPTION_STRING(set_tls_auth_password, native::CURLOPT_TLSAUTH_PASSWORD); 266 | IMPLEMENT_CURL_OPTION(set_proxy_auth, native::CURLOPT_PROXYAUTH, long); 267 | 268 | // HTTP options 269 | 270 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_auto_referrer, native::CURLOPT_AUTOREFERER); 271 | IMPLEMENT_CURL_OPTION_STRING(set_accept_encoding, native::CURLOPT_ACCEPT_ENCODING); 272 | IMPLEMENT_CURL_OPTION_STRING(set_transfer_encoding, native::CURLOPT_TRANSFER_ENCODING); 273 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_follow_location, native::CURLOPT_FOLLOWLOCATION); 274 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_unrestricted_auth, native::CURLOPT_UNRESTRICTED_AUTH); 275 | IMPLEMENT_CURL_OPTION(set_max_redirs, native::CURLOPT_MAXREDIRS, long); 276 | IMPLEMENT_CURL_OPTION(set_post_redir, native::CURLOPT_POSTREDIR, long); 277 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_post, native::CURLOPT_POST); 278 | void set_post_fields(const std::string& post_fields); 279 | void set_post_fields(const std::string& post_fields, boost::system::error_code& ec); 280 | IMPLEMENT_CURL_OPTION(set_post_fields, native::CURLOPT_POSTFIELDS, void*); 281 | IMPLEMENT_CURL_OPTION(set_post_field_size, native::CURLOPT_POSTFIELDSIZE, long); 282 | IMPLEMENT_CURL_OPTION(set_post_field_size_large, native::CURLOPT_POSTFIELDSIZE_LARGE, native::curl_off_t); 283 | void set_http_post(boost::shared_ptr form); 284 | void set_http_post(boost::shared_ptr form, boost::system::error_code& ec); 285 | IMPLEMENT_CURL_OPTION_STRING(set_referer, native::CURLOPT_REFERER); 286 | IMPLEMENT_CURL_OPTION_STRING(set_user_agent, native::CURLOPT_USERAGENT); 287 | void add_header(const std::string& name, const std::string& value); 288 | void add_header(const std::string& name, const std::string& value, boost::system::error_code& ec); 289 | void add_header(const std::string& header); 290 | void add_header(const std::string& header, boost::system::error_code& ec); 291 | void set_headers(boost::shared_ptr headers); 292 | void set_headers(boost::shared_ptr headers, boost::system::error_code& ec); 293 | void add_http200_alias(const std::string& http200_alias); 294 | void add_http200_alias(const std::string& http200_alias, boost::system::error_code& ec); 295 | void set_http200_aliases(boost::shared_ptr http200_aliases); 296 | void set_http200_aliases(boost::shared_ptr http200_aliases, boost::system::error_code& ec); 297 | IMPLEMENT_CURL_OPTION_STRING(set_cookie, native::CURLOPT_COOKIE); 298 | IMPLEMENT_CURL_OPTION_STRING(set_cookie_file, native::CURLOPT_COOKIEFILE); 299 | IMPLEMENT_CURL_OPTION_STRING(set_cookie_jar, native::CURLOPT_COOKIEJAR); 300 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_cookie_session, native::CURLOPT_COOKIESESSION); 301 | IMPLEMENT_CURL_OPTION_STRING(set_cookie_list, native::CURLOPT_COOKIELIST); 302 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_get, native::CURLOPT_HTTPGET); 303 | enum http_version_t { http_version_none = native::CURL_HTTP_VERSION_NONE, http_version_1_0 = native::CURL_HTTP_VERSION_1_0, http_version_1_1 = native::CURL_HTTP_VERSION_1_1 }; 304 | IMPLEMENT_CURL_OPTION_ENUM(set_http_version, native::CURLOPT_HTTP_VERSION, http_version_t, long); 305 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ignore_content_length, native::CURLOPT_IGNORE_CONTENT_LENGTH); 306 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_content_decoding, native::CURLOPT_HTTP_CONTENT_DECODING); 307 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_http_transfer_decoding, native::CURLOPT_HTTP_TRANSFER_DECODING); 308 | 309 | // SMTP options 310 | 311 | IMPLEMENT_CURL_OPTION_STRING(set_mail_from, native::CURLOPT_MAIL_FROM); 312 | void add_mail_rcpt(const std::string& mail_rcpt); 313 | void add_mail_rcpt(const std::string& mail_rcpt, boost::system::error_code& ec); 314 | void set_mail_rcpts(boost::shared_ptr mail_rcpts); 315 | void set_mail_rcpts(boost::shared_ptr mail_rcpts, boost::system::error_code& ec); 316 | IMPLEMENT_CURL_OPTION_STRING(set_mail_auth, native::CURLOPT_MAIL_AUTH); 317 | 318 | // TFTP options 319 | 320 | IMPLEMENT_CURL_OPTION(set_tftp_blksize, native::CURLOPT_TFTP_BLKSIZE, long); 321 | 322 | // FTP options 323 | 324 | IMPLEMENT_CURL_OPTION_STRING(set_ftp_port, native::CURLOPT_FTPPORT); 325 | void add_quote(const std::string& quote); 326 | void add_quote(const std::string& quote, boost::system::error_code& ec); 327 | void set_quotes(boost::shared_ptr quotes); 328 | void set_quotes(boost::shared_ptr quotes, boost::system::error_code& ec); 329 | /*void add_post_quote(const std::string& pre_quote); 330 | void set_post_quotes(boost::shared_ptr pre_quotes); 331 | void add_pre_quote(const std::string& pre_quote); 332 | void set_pre_quotes(boost::shared_ptr pre_quotes);*/ 333 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_dir_list_only, native::CURLOPT_DIRLISTONLY); 334 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_append, native::CURLOPT_APPEND); 335 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ftp_use_eprt, native::CURLOPT_FTP_USE_EPRT); 336 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ftp_use_epsv, native::CURLOPT_FTP_USE_EPSV); 337 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ftp_use_pret, native::CURLOPT_FTP_USE_PRET); 338 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ftp_create_missing_dirs, native::CURLOPT_FTP_CREATE_MISSING_DIRS); 339 | IMPLEMENT_CURL_OPTION(set_ftp_response_timeout, native::CURLOPT_FTP_RESPONSE_TIMEOUT, long); 340 | IMPLEMENT_CURL_OPTION_STRING(set_ftp_alternative_to_user, native::CURLOPT_FTP_ALTERNATIVE_TO_USER); 341 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ftp_skip_pasv_ip, native::CURLOPT_FTP_SKIP_PASV_IP); 342 | enum ftp_ssl_auth_t { ftp_auth_default = native::CURLFTPAUTH_DEFAULT, ftp_auth_ssl = native::CURLFTPAUTH_SSL, ftp_auth_tls = native::CURLFTPAUTH_TLS }; 343 | IMPLEMENT_CURL_OPTION_ENUM(set_ftp_ssl_auth, native::CURLOPT_FTPSSLAUTH, ftp_ssl_auth_t, long); 344 | enum ftp_ssl_ccc_t { ftp_ssl_ccc_none = native::CURLFTPSSL_CCC_NONE, ftp_ssl_ccc_passive = native::CURLFTPSSL_CCC_PASSIVE, ftp_ssl_ccc_active = native::CURLFTPSSL_CCC_ACTIVE }; 345 | IMPLEMENT_CURL_OPTION_ENUM(set_ftp_ssl_ccc, native::CURLOPT_FTP_SSL_CCC, ftp_ssl_ccc_t, long); 346 | IMPLEMENT_CURL_OPTION_STRING(set_ftp_account, native::CURLOPT_FTP_ACCOUNT); 347 | enum ftp_file_method_t { ftp_method_multi_cwd = native::CURLFTPMETHOD_MULTICWD , ftp_method_no_cwd = native::CURLFTPMETHOD_NOCWD, ftp_method_single_cwd = native::CURLFTPMETHOD_SINGLECWD }; 348 | IMPLEMENT_CURL_OPTION_ENUM(set_ftp_file_method, native::CURLOPT_FTP_FILEMETHOD, ftp_file_method_t, long); 349 | 350 | // RTSP options 351 | 352 | enum rtsp_request_t 353 | { 354 | rtsp_request_options = native::CURL_RTSPREQ_OPTIONS, 355 | rtsp_request_describe = native::CURL_RTSPREQ_DESCRIBE, 356 | rtsp_request_announce = native::CURL_RTSPREQ_ANNOUNCE, 357 | rtsp_request_setup = native::CURL_RTSPREQ_SETUP, 358 | rtsp_request_play = native::CURL_RTSPREQ_PLAY, 359 | rtsp_request_pause = native::CURL_RTSPREQ_PAUSE, 360 | rtsp_request_teardown = native::CURL_RTSPREQ_TEARDOWN, 361 | rtsp_request_get_parameter = native::CURL_RTSPREQ_GET_PARAMETER, 362 | rtsp_request_set_parameter = native::CURL_RTSPREQ_SET_PARAMETER, 363 | rtsp_request_record = native::CURL_RTSPREQ_RECORD, 364 | rtsp_request_receive = native::CURL_RTSPREQ_RECEIVE 365 | }; 366 | IMPLEMENT_CURL_OPTION_ENUM(set_rtsp_request, native::CURLOPT_RTSP_REQUEST, rtsp_request_t, long); 367 | IMPLEMENT_CURL_OPTION_STRING(set_rtsp_session_id, native::CURLOPT_RTSP_SESSION_ID); 368 | IMPLEMENT_CURL_OPTION_STRING(set_rtsp_stream_uri, native::CURLOPT_RTSP_STREAM_URI); 369 | IMPLEMENT_CURL_OPTION_STRING(set_rtsp_transport, native::CURLOPT_RTSP_TRANSPORT); 370 | IMPLEMENT_CURL_OPTION(set_rtsp_client_cseq, native::CURLOPT_RTSP_CLIENT_CSEQ, long); 371 | IMPLEMENT_CURL_OPTION(set_rtsp_server_cseq, native::CURLOPT_RTSP_SERVER_CSEQ, long); 372 | 373 | // protocol options 374 | 375 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_transfer_text, native::CURLOPT_TRANSFERTEXT); 376 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_transfer_mode, native::CURLOPT_PROXY_TRANSFER_MODE); 377 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_crlf, native::CURLOPT_CRLF); 378 | IMPLEMENT_CURL_OPTION_STRING(set_range, native::CURLOPT_RANGE); 379 | IMPLEMENT_CURL_OPTION(set_resume_from, native::CURLOPT_RESUME_FROM, long); 380 | IMPLEMENT_CURL_OPTION(set_resume_from_large, native::CURLOPT_RESUME_FROM_LARGE, native::curl_off_t); 381 | IMPLEMENT_CURL_OPTION_STRING(set_custom_request, native::CURLOPT_CUSTOMREQUEST); 382 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_file_time, native::CURLOPT_FILETIME); 383 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_no_body, native::CURLOPT_NOBODY); 384 | IMPLEMENT_CURL_OPTION(set_in_file_size, native::CURLOPT_INFILESIZE, long); 385 | IMPLEMENT_CURL_OPTION(set_in_file_size_large, native::CURLOPT_INFILESIZE_LARGE, native::curl_off_t); 386 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_upload, native::CURLOPT_UPLOAD); 387 | IMPLEMENT_CURL_OPTION(set_max_file_size, native::CURLOPT_MAXFILESIZE, long); 388 | IMPLEMENT_CURL_OPTION(set_max_file_size_large, native::CURLOPT_MAXFILESIZE_LARGE, native::curl_off_t); 389 | enum time_condition_t { if_modified_since = native::CURL_TIMECOND_IFMODSINCE, if_unmodified_since = native::CURL_TIMECOND_IFUNMODSINCE }; 390 | IMPLEMENT_CURL_OPTION_ENUM(set_time_condition, native::CURLOPT_TIMECONDITION, time_condition_t, long); 391 | IMPLEMENT_CURL_OPTION(set_time_value, native::CURLOPT_TIMEVALUE, long); 392 | 393 | // connection options 394 | 395 | IMPLEMENT_CURL_OPTION(set_timeout, native::CURLOPT_TIMEOUT, long); 396 | IMPLEMENT_CURL_OPTION(set_timeout_ms, native::CURLOPT_TIMEOUT_MS, long); 397 | IMPLEMENT_CURL_OPTION(set_low_speed_limit, native::CURLOPT_LOW_SPEED_LIMIT, long); 398 | IMPLEMENT_CURL_OPTION(set_low_speed_time, native::CURLOPT_LOW_SPEED_TIME, long); 399 | IMPLEMENT_CURL_OPTION(set_max_send_speed_large, native::CURLOPT_MAX_SEND_SPEED_LARGE, native::curl_off_t); 400 | IMPLEMENT_CURL_OPTION(set_max_recv_speed_large, native::CURLOPT_MAX_RECV_SPEED_LARGE, native::curl_off_t); 401 | IMPLEMENT_CURL_OPTION(set_max_connects, native::CURLOPT_MAXCONNECTS, long); 402 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_fresh_connect, native::CURLOPT_FRESH_CONNECT); 403 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_forbot_reuse, native::CURLOPT_FORBID_REUSE); 404 | IMPLEMENT_CURL_OPTION(set_connect_timeout, native::CURLOPT_CONNECTTIMEOUT, long); 405 | IMPLEMENT_CURL_OPTION(set_connect_timeout_ms, native::CURLOPT_CONNECTTIMEOUT_MS, long); 406 | enum ip_resolve_t { ip_resolve_whatever = CURL_IPRESOLVE_WHATEVER, ip_resolve_v4 = CURL_IPRESOLVE_V4, ip_resolve_v6 = CURL_IPRESOLVE_V6 }; 407 | IMPLEMENT_CURL_OPTION_ENUM(set_ip_resolve, native::CURLOPT_IPRESOLVE, ip_resolve_t, long); 408 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_connect_only, native::CURLOPT_CONNECT_ONLY); 409 | enum use_ssl_t { use_ssl_none = native::CURLUSESSL_NONE, use_ssl_try = native::CURLUSESSL_TRY, use_ssl_control = native::CURLUSESSL_CONTROL, use_ssl_all = native::CURLUSESSL_ALL }; 410 | IMPLEMENT_CURL_OPTION_ENUM(set_use_ssl, native::CURLOPT_USE_SSL, use_ssl_t, long); 411 | void add_resolve(const std::string& resolved_host); 412 | void add_resolve(const std::string& resolved_host, boost::system::error_code& ec); 413 | void set_resolves(boost::shared_ptr resolved_hosts); 414 | void set_resolves(boost::shared_ptr resolved_hosts, boost::system::error_code& ec); 415 | IMPLEMENT_CURL_OPTION_STRING(set_dns_servers, native::CURLOPT_DNS_SERVERS); 416 | IMPLEMENT_CURL_OPTION(set_accept_timeout_ms, native::CURLOPT_ACCEPTTIMEOUT_MS, long); 417 | 418 | // SSL and security options 419 | 420 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_cert, native::CURLOPT_SSLCERT); 421 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_cert_type, native::CURLOPT_SSLCERTTYPE); 422 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_key, native::CURLOPT_SSLKEY); 423 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_key_type, native::CURLOPT_SSLKEYTYPE); 424 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_key_passwd, native::CURLOPT_KEYPASSWD); 425 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_engine, native::CURLOPT_SSLENGINE); 426 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_engine_default, native::CURLOPT_SSLENGINE_DEFAULT); 427 | enum ssl_version_t { ssl_version_default = native::CURL_SSLVERSION_DEFAULT, ssl_version_tls_v1 = native::CURL_SSLVERSION_TLSv1, ssl_version_ssl_v2 = native::CURL_SSLVERSION_SSLv2, ssl_version_ssl_v3 = native::CURL_SSLVERSION_SSLv3 }; 428 | IMPLEMENT_CURL_OPTION_ENUM(set_ssl_version, native::CURLOPT_SSLVERSION, ssl_version_t, long); 429 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ssl_verify_peer, native::CURLOPT_SSL_VERIFYPEER); 430 | IMPLEMENT_CURL_OPTION_STRING(set_ca_info, native::CURLOPT_CAINFO); 431 | IMPLEMENT_CURL_OPTION_STRING(set_issuer_cert, native::CURLOPT_ISSUERCERT); 432 | IMPLEMENT_CURL_OPTION_STRING(set_ca_file, native::CURLOPT_CAPATH); 433 | IMPLEMENT_CURL_OPTION_STRING(set_crl_file, native::CURLOPT_CRLFILE); 434 | inline void set_ssl_verify_host(bool verify_host) 435 | { 436 | boost::system::error_code ec; 437 | set_ssl_verify_host(verify_host, ec); 438 | boost::asio::detail::throw_error(ec); 439 | } 440 | inline void set_ssl_verify_host(bool verify_host, boost::system::error_code& ec) 441 | { 442 | ec = boost::system::error_code(curl_easy_setopt(handle_, native::CURLOPT_SSL_VERIFYHOST, verify_host ? 2L : 0L)); 443 | } 444 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_cert_info, native::CURLOPT_CERTINFO); 445 | IMPLEMENT_CURL_OPTION_STRING(set_random_file, native::CURLOPT_RANDOM_FILE); 446 | IMPLEMENT_CURL_OPTION_STRING(set_edg_socket, native::CURLOPT_EGDSOCKET); 447 | IMPLEMENT_CURL_OPTION_STRING(set_ssl_cipher_list, native::CURLOPT_SSL_CIPHER_LIST); 448 | IMPLEMENT_CURL_OPTION_BOOLEAN(set_ssl_session_id_cache, native::CURLOPT_SSL_SESSIONID_CACHE); 449 | IMPLEMENT_CURL_OPTION(set_ssl_options, native::CURLOPT_SSL_OPTIONS, long); 450 | IMPLEMENT_CURL_OPTION_STRING(set_krb_level, native::CURLOPT_KRBLEVEL); 451 | IMPLEMENT_CURL_OPTION(set_gssapi_delegation, native::CURLOPT_GSSAPI_DELEGATION, long); 452 | 453 | // SSH options 454 | 455 | IMPLEMENT_CURL_OPTION(set_ssh_auth_types, native::CURLOPT_SSH_AUTH_TYPES, long); 456 | IMPLEMENT_CURL_OPTION_STRING(set_ssh_host_public_key_md5, native::CURLOPT_SSH_HOST_PUBLIC_KEY_MD5); 457 | IMPLEMENT_CURL_OPTION_STRING(set_ssh_public_key_file, native::CURLOPT_SSH_PUBLIC_KEYFILE); 458 | IMPLEMENT_CURL_OPTION_STRING(set_ssh_private_key_file, native::CURLOPT_SSH_PRIVATE_KEYFILE); 459 | IMPLEMENT_CURL_OPTION_STRING(set_ssh_known_hosts, native::CURLOPT_SSH_KNOWNHOSTS); 460 | IMPLEMENT_CURL_OPTION(set_ssh_key_function, native::CURLOPT_SSH_KEYFUNCTION, void*); // TODO curl_sshkeycallback? 461 | IMPLEMENT_CURL_OPTION(set_ssh_key_data, native::CURLOPT_SSH_KEYDATA, void*); 462 | 463 | // other options 464 | 465 | IMPLEMENT_CURL_OPTION(set_private, native::CURLOPT_PRIVATE, void*); 466 | void set_share(boost::shared_ptr share); 467 | void set_share(boost::shared_ptr share, boost::system::error_code& ec); 468 | IMPLEMENT_CURL_OPTION(set_new_file_perms, native::CURLOPT_NEW_FILE_PERMS, long); 469 | IMPLEMENT_CURL_OPTION(set_new_directory_perms, native::CURLOPT_NEW_DIRECTORY_PERMS, long); 470 | 471 | // telnet options 472 | 473 | void add_telnet_option(const std::string& option, const std::string& value); 474 | void add_telnet_option(const std::string& option, const std::string& value, boost::system::error_code& ec); 475 | void add_telnet_option(const std::string& telnet_option); 476 | void add_telnet_option(const std::string& telnet_option, boost::system::error_code& ec); 477 | void set_telnet_options(boost::shared_ptr telnet_options); 478 | void set_telnet_options(boost::shared_ptr telnet_options, boost::system::error_code& ec); 479 | 480 | // getters 481 | 482 | IMPLEMENT_CURL_OPTION_GET_STRING(get_effective_url, native::CURLINFO_EFFECTIVE_URL); 483 | IMPLEMENT_CURL_OPTION_GET_LONG(get_reponse_code, native::CURLINFO_RESPONSE_CODE); 484 | IMPLEMENT_CURL_OPTION_GET_LONG(get_http_connectcode, native::CURLINFO_HTTP_CONNECTCODE); 485 | IMPLEMENT_CURL_OPTION_GET_LONG(get_filetime, native::CURLINFO_FILETIME); 486 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_total_time, native::CURLINFO_TOTAL_TIME); 487 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_namelookup_time, native::CURLINFO_NAMELOOKUP_TIME); 488 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_connect_time, native::CURLINFO_CONNECT_TIME); 489 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_appconnect_time, native::CURLINFO_APPCONNECT_TIME); 490 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_pretransfer_time, native::CURLINFO_PRETRANSFER_TIME); 491 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_starttransfer_time, native::CURLINFO_STARTTRANSFER_TIME); 492 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_redirect_time, native::CURLINFO_REDIRECT_TIME); 493 | IMPLEMENT_CURL_OPTION_GET_LONG(get_redirect_count, native::CURLINFO_REDIRECT_COUNT); 494 | IMPLEMENT_CURL_OPTION_GET_STRING(get_redirect_url, native::CURLINFO_REDIRECT_URL); 495 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_size_upload, native::CURLINFO_SIZE_UPLOAD); 496 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_size_download, native::CURLINFO_SIZE_DOWNLOAD); 497 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_speed_download, native::CURLINFO_SPEED_DOWNLOAD); 498 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_speed_upload, native::CURLINFO_SPEED_UPLOAD); 499 | IMPLEMENT_CURL_OPTION_GET_LONG(get_header_size, native::CURLINFO_HEADER_SIZE); 500 | IMPLEMENT_CURL_OPTION_GET_LONG(get_request_size, native::CURLINFO_REQUEST_SIZE); 501 | IMPLEMENT_CURL_OPTION_GET_LONG(get_ssl_verifyresult, native::CURLINFO_SSL_VERIFYRESULT); 502 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_content_length_download, native::CURLINFO_CONTENT_LENGTH_DOWNLOAD); 503 | IMPLEMENT_CURL_OPTION_GET_DOUBLE(get_content_length_upload, native::CURLINFO_CONTENT_LENGTH_UPLOAD); 504 | IMPLEMENT_CURL_OPTION_GET_STRING(get_content_type, native::CURLINFO_CONTENT_TYPE); 505 | IMPLEMENT_CURL_OPTION_GET_LONG(get_httpauth_avail, native::CURLINFO_HTTPAUTH_AVAIL); 506 | IMPLEMENT_CURL_OPTION_GET_LONG(get_proxyauth_avail, native::CURLINFO_PROXYAUTH_AVAIL); 507 | IMPLEMENT_CURL_OPTION_GET_LONG(get_os_errno, native::CURLINFO_OS_ERRNO); 508 | IMPLEMENT_CURL_OPTION_GET_LONG(get_num_connects, native::CURLINFO_NUM_CONNECTS); 509 | IMPLEMENT_CURL_OPTION_GET_STRING(get_primary_ip, native::CURLINFO_PRIMARY_IP); 510 | IMPLEMENT_CURL_OPTION_GET_LONG(get_primary_port, native::CURLINFO_PRIMARY_PORT); 511 | IMPLEMENT_CURL_OPTION_GET_STRING(get_local_ip, native::CURLINFO_LOCAL_IP); 512 | IMPLEMENT_CURL_OPTION_GET_LONG(get_local_port, native::CURLINFO_LOCAL_PORT); 513 | IMPLEMENT_CURL_OPTION_GET_LONG(get_last_socket, native:: CURLINFO_LASTSOCKET); 514 | IMPLEMENT_CURL_OPTION_GET_STRING(get_ftp_entry_path, native::CURLINFO_FTP_ENTRY_PATH); 515 | IMPLEMENT_CURL_OPTION_GET_LONG(get_condition_unmet, native:: CURLINFO_CONDITION_UNMET); 516 | IMPLEMENT_CURL_OPTION_GET_STRING(get_rtsp_session_id, native::CURLINFO_RTSP_SESSION_ID); 517 | IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_client_cseq, native::CURLINFO_RTSP_CLIENT_CSEQ); 518 | IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_server_cseq, native::CURLINFO_RTSP_SERVER_CSEQ); 519 | IMPLEMENT_CURL_OPTION_GET_LONG(get_rtsp_cseq_recv, native::CURLINFO_RTSP_CSEQ_RECV); 520 | IMPLEMENT_CURL_OPTION_GET_LIST(get_ssl_engines, native::CURLINFO_SSL_ENGINES); 521 | IMPLEMENT_CURL_OPTION_GET_LIST(get_cookielist, native::CURLINFO_COOKIELIST); 522 | // CURLINFO_PRIVATE 523 | // CURLINFO_CERTINFO 524 | // CURLINFO_TLS_SESSION 525 | 526 | inline bool operator<(const easy& other) const 527 | { 528 | return (this < &other); 529 | } 530 | 531 | void handle_completion(const boost::system::error_code& err); 532 | 533 | private: 534 | void init(); 535 | native::curl_socket_t open_tcp_socket(native::curl_sockaddr* address); 536 | 537 | static size_t write_function(char* ptr, size_t size, size_t nmemb, void* userdata); 538 | static size_t read_function(void* ptr, size_t size, size_t nmemb, void* userdata); 539 | static int seek_function(void* instream, native::curl_off_t offset, int origin); 540 | #if LIBCURL_VERSION_NUM < 0x072000 541 | static int progress_function(void* clientp, double dltotal, double dlnow, double ultotal, double ulnow); 542 | #else 543 | static int xferinfo_function(void* clientp, native::curl_off_t dltotal, native::curl_off_t dlnow, native::curl_off_t ultotal, native::curl_off_t ulnow); 544 | #endif 545 | static native::curl_socket_t opensocket(void* clientp, native::curlsocktype purpose, struct native::curl_sockaddr* address); 546 | static int closesocket(void* clientp, native::curl_socket_t item); 547 | 548 | boost::asio::io_service& io_service_; 549 | initialization::ptr initref_; 550 | native::CURL* handle_; 551 | multi* multi_; 552 | bool multi_registered_; 553 | handler_type handler_; 554 | boost::shared_ptr source_; 555 | boost::shared_ptr sink_; 556 | std::string post_fields_; 557 | boost::shared_ptr form_; 558 | boost::shared_ptr headers_; 559 | boost::shared_ptr http200_aliases_; 560 | boost::shared_ptr mail_rcpts_; 561 | boost::shared_ptr quotes_; 562 | boost::shared_ptr resolved_hosts_; 563 | boost::shared_ptr share_; 564 | boost::shared_ptr telnet_options_; 565 | progress_callback_t progress_callback_; 566 | }; 567 | } 568 | 569 | #undef IMPLEMENT_CURL_OPTION 570 | #undef IMPLEMENT_CURL_OPTION_BOOLEAN 571 | #undef IMPLEMENT_CURL_OPTION_ENUM 572 | #undef IMPLEMENT_CURL_OPTION_STRING 573 | #undef IMPLEMENT_CURL_OPTION_GET_STRING 574 | #undef IMPLEMENT_CURL_OPTION_GET_DOUBLE 575 | #undef IMPLEMENT_CURL_OPTION_GET_LONG 576 | #undef IMPLEMENT_CURL_OPTION_GET_LIST 577 | --------------------------------------------------------------------------------