diff --git a/CMakeLists.txt b/CMakeLists.txt
index 43d7dee70..b5f7cdec2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -42,6 +42,21 @@ message("PATH: $ENV{PATH}")
message("PERL5LIB: $ENV{PERL5LIB}")
find_package(Perl REQUIRED)
+# CMAKE_PREFIX_PATH is used to point CMake to the remaining dependencies (Boost, TBB, ...)
+# We pick it from environment if it is not defined in another way
+if(NOT DEFINED CMAKE_PREFIX_PATH)
+ if(DEFINED ENV{CMAKE_PREFIX_PATH})
+ set(CMAKE_PREFIX_PATH "$ENV{CMAKE_PREFIX_PATH}")
+ endif()
+endif()
+
+if (MSVC)
+ # By default the startup project in MSVC is the 'ALL_BUILD' cmake-created project,
+ # but we want 'slic3r' as the startup one because debugging run command is associated with it.
+ # (Unfortunatelly it cannot be associated with ALL_BUILD using CMake.)
+ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT slic3r)
+endif ()
+
add_subdirectory(xs)
enable_testing ()
diff --git a/cmake/modules/FindCURL.cmake b/cmake/modules/FindCURL.cmake
new file mode 100644
index 000000000..b8724858c
--- /dev/null
+++ b/cmake/modules/FindCURL.cmake
@@ -0,0 +1,59 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+#.rst:
+# FindCURL
+# --------
+#
+# Find curl
+#
+# Find the native CURL headers and libraries.
+#
+# ::
+#
+# CURL_INCLUDE_DIRS - where to find curl/curl.h, etc.
+# CURL_LIBRARIES - List of libraries when using curl.
+# CURL_FOUND - True if curl found.
+# CURL_VERSION_STRING - the version of curl found (since CMake 2.8.8)
+
+# Look for the header file.
+find_path(CURL_INCLUDE_DIR NAMES curl/curl.h)
+mark_as_advanced(CURL_INCLUDE_DIR)
+
+# Look for the library (sorted from most current/relevant entry to least).
+find_library(CURL_LIBRARY NAMES
+ curl
+ # Windows MSVC Makefile:
+ libcurl_a
+ # Windows MSVC prebuilts:
+ curllib
+ libcurl_imp
+ curllib_static
+ # Windows older "Win32 - MSVC" prebuilts (libcurl.lib, e.g. libcurl-7.15.5-win32-msvc.zip):
+ libcurl
+)
+mark_as_advanced(CURL_LIBRARY)
+
+if(CURL_INCLUDE_DIR)
+ foreach(_curl_version_header curlver.h curl.h)
+ if(EXISTS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}")
+ file(STRINGS "${CURL_INCLUDE_DIR}/curl/${_curl_version_header}" curl_version_str REGEX "^#define[\t ]+LIBCURL_VERSION[\t ]+\".*\"")
+
+ string(REGEX REPLACE "^#define[\t ]+LIBCURL_VERSION[\t ]+\"([^\"]*)\".*" "\\1" CURL_VERSION_STRING "${curl_version_str}")
+ unset(curl_version_str)
+ break()
+ endif()
+ endforeach()
+endif()
+
+find_package_handle_standard_args(CURL
+ REQUIRED_VARS CURL_LIBRARY CURL_INCLUDE_DIR
+ VERSION_VAR CURL_VERSION_STRING)
+
+if(CURL_FOUND)
+ set(CURL_LIBRARIES ${CURL_LIBRARY})
+ set(CURL_INCLUDE_DIRS ${CURL_INCLUDE_DIR})
+
+ message(STATUS " Curl libraries: = ${CURL_LIBRARIES}")
+ message(STATUS " Curl include dirs: = ${CURL_INCLUDE_DIRS}")
+endif()
diff --git a/cmake/msvc/slic3r.wperl64d.props b/cmake/msvc/slic3r.wperl64d.props
new file mode 100644
index 000000000..68dac2085
--- /dev/null
+++ b/cmake/msvc/slic3r.wperl64d.props
@@ -0,0 +1,9 @@
+
+
+
+ C:\wperl64d\bin\perl.exe
+ slic3r.pl
+ WindowsLocalDebugger
+ ..\..
+
+
diff --git a/cmake/msvc/xs.wperl64d.props b/cmake/msvc/xs.wperl64d.props
new file mode 100644
index 000000000..101923581
--- /dev/null
+++ b/cmake/msvc/xs.wperl64d.props
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ $(VC_ExecutablePath_x64);$(WindowsSDK_ExecutablePath);$(VS_ExecutablePath);$(MSBuild_ExecutablePath);$(FxCopDir);$(PATH);c:\wperl64d\bin\;
+
+
+
+
diff --git a/doc/How to build - UNIX.md b/doc/How to build - UNIX.md
new file mode 100644
index 000000000..77ce54419
--- /dev/null
+++ b/doc/How to build - UNIX.md
@@ -0,0 +1,2 @@
+# Building Slic3r PE on Linux/UNIX
+
diff --git a/doc/How to build - Windows.md b/doc/How to build - Windows.md
new file mode 100644
index 000000000..8209954bd
--- /dev/null
+++ b/doc/How to build - Windows.md
@@ -0,0 +1,86 @@
+# Building Slic3r PE on Microsoft Windows
+
+The currently supported way of building Slic3r PE on Windows is with MS Visual Studio 2013
+using our Perl binary distribution (compiled from official Perl sources).
+You can use the free [Visual Studio 2013 Community Edition](https://www.visualstudio.com/vs/older-downloads/).
+
+Other setups (such as mingw + Strawberry Perl) _may_ work, but we cannot guarantee this will work
+and cannot provide guidance.
+
+
+### Geting the dependencies
+
+First, download and upnack our Perl + wxWidgets binary distribution:
+
+ - 32 bit, release mode: [wperl32-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl32-5.24.0-2018-03-02.7z)
+ - 64 bit, release mode: [wperl64-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64-5.24.0-2018-03-02.7z)
+ - 64 bit, release mode + debug symbols: [wperl64d-5.24.0-2018-03-02.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=wperl64d-5.24.0-2018-03-02.7z)
+
+It is recommended to unpack this package into `C:\`.
+
+Apart from wxWidgets and Perl, you will also need additional dependencies:
+
+ - Boost
+ - Intel TBB
+ - libcurl
+
+We have prepared a binary package of the listed libraries:
+
+ - 32 bit: [slic3r-destdir-32.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-32.7z)
+ - 64 bit: [slic3r-destdir-64.7z](https://bintray.com/vojtechkral/Slic3r-PE/download_file?file_path=slic3r-destdir-64.7z)
+
+It is recommended you unpack this package into `C:\local\` as the environment
+setup script expects it there.
+
+Alternatively you can also compile the additional dependencies yourself.
+There is a [powershell script](./deps-build/windows/slic3r-makedeps.ps1) which automates this process.
+
+### Building Slic3r PE
+
+Once the dependencies are set up in their respective locations,
+go to the `wperl*` directory extracted earlier and launch the `cmdline.lnk` file
+which opens a command line prompt with appropriate environment variables set up.
+
+In this command line, `cd` into the directory with Slic3r sources
+and use these commands to build the Slic3r from the command line:
+
+ perl Build.PL
+ perl Build.PL --gui
+ mkdir build
+ cd build
+ cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE=Release
+ nmake
+ ctest --verbose # TODO: ???
+ cd ..
+ perl slic3r.pl
+
+The above commands use `nmake` Makefiles.
+You may also build Slic3r PE with other build tools:
+
+
+### Building with Visual Studio
+
+To build, lanuch and/or debug Slic3r PE with Visual Studio (64 bits), replace the `cmake` command with:
+
+ cmake .. -G "Visual Studio 12 Win64" -DCMAKE_CONFIGURATION_TYPES=Release;RelWithDebInfo || exit /b
+
+For the 32-bit variant, use:
+
+ cmake .. -G "Visual Studio 12" -DCMAKE_CONFIGURATION_TYPES=Release;RelWithDebInfo || exit /b
+
+After `cmake` has finished, go to the `Slic3r\build` directory and open the `Slic3r.sln` solution file.
+This should open Visual Studio and load all the Slic3r solution containing all the projects.
+Make sure you use Visual Studio 2013 to open the solution.
+
+You can then use the usual Visual Studio controls to build Slic3r.
+If you want to run or debug Slic3r from within Visual Studio, make sure the `slic3r` project is activated.
+There are multiple projects in the Slic3r solution, but only the `slic3r` project is configured with the right
+commands to run Slic3r.
+
+
+### Building with ninja
+
+To use [Ninja](TODO), replace the `cmake` and `nmake` commands with:
+
+ cmake .. -G Ninja -DCMAKE_BUILD_TYPE=Release
+ ninja
diff --git a/doc/deps-build/unix-static/Makefile b/doc/deps-build/unix-static/Makefile
new file mode 100644
index 000000000..e7588b994
--- /dev/null
+++ b/doc/deps-build/unix-static/Makefile
@@ -0,0 +1,132 @@
+
+#
+# This makefile downloads, configures and builds Slic3r PE dependencies for Unix.
+# (That is, all dependencies except perl + wxWidgets.)
+# The libraries are installed in DESTDIR, which you can customize like so:
+#
+# DESTDIR=foo/bar make
+#
+# The default DESTDIR is ~/slic3r-destdir
+# If the DESTDIR doesn't exits, the makefile tries to create it
+#
+# To pass the DESTDIR path along to cmake, set the use CMAKE_PREFIX_PATH variable
+# and set it to $DESTDIR/usr/local
+#
+# You can also customize the NPROC variable in the same way to configure the number
+# of cores the build process uses. By default this is set to what the `nproc` command says.
+#
+
+
+DESTDIR ?= $(HOME)/slic3r-destdir
+NPROC ?= $(shell nproc)
+
+
+BOOST = boost_1_66_0
+TBB_SHA = a0dc9bf76d0120f917b641ed095360448cabc85b
+TBB = tbb-$(TBB_SHA)
+OPENSSL = openssl-OpenSSL_1_1_0g
+CURL = curl-7.58.0
+
+.PHONY: all destdir boost libcurl libopenssl libtbb
+
+all: destdir boost libtbb libcurl
+ @echo
+ @echo "All done!"
+ @echo
+
+destdir:
+ mkdir -p $(DESTDIR)
+
+
+
+boost: $(BOOST).tar.gz
+ tar -zxvf $(BOOST).tar.gz
+ cd $(BOOST) && ./bootstrap.sh --with-libraries=system,filesystem,thread,log,locale,regex --prefix=$(DESTDIR)/usr/local
+ cd $(BOOST) && ./b2 \
+ -j $(NPROC) \
+ link=static \
+ variant=release \
+ threading=multi \
+ boost.locale.icu=off \
+ cxxflags=-fPIC cflags=-fPIC \
+ install
+
+$(BOOST).tar.gz:
+ curl -L -o $@ https://dl.bintray.com/boostorg/release/1.66.0/source/$@
+
+
+
+libtbb: $(TBB).tar.gz
+ tar -zxvf $(TBB).tar.gz
+ mkdir -p $(TBB)/mybuild
+ cd $(TBB)/mybuild && cmake .. -DTBB_BUILD_SHARED=OFF -DTBB_BUILD_TESTS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON
+ $(MAKE) -C $(TBB)/mybuild -j$(NPROC)
+ $(MAKE) -C $(TBB)/mybuild install DESTDIR=$(DESTDIR)
+
+$(TBB).tar.gz:
+ curl -L -o $@ https://github.com/wjakob/tbb/archive/$(TBB_SHA).tar.gz
+
+
+
+libopenssl: $(OPENSSL).tar.gz
+ tar -zxvf $(OPENSSL).tar.gz
+ cd $(OPENSSL) && ./config --openssldir=/etc/ssl shared no-ssl3-method no-dynamic-engine '-Wa,--noexecstack'
+ make -C $(OPENSSL) depend
+ make -C $(OPENSSL) -j$(NPROC)
+ make -C $(OPENSSL) install DESTDIR=$(DESTDIR)
+
+$(OPENSSL).tar.gz:
+ curl -L -o $@ 'https://github.com/openssl/openssl/archive/OpenSSL_1_1_0g.tar.gz'
+
+
+
+libcurl: libopenssl $(CURL).tar.gz
+ tar -zxvf $(CURL).tar.gz
+# XXX: disable shared?
+# Setting PKG_CONFIG_PATH should make libcurl find our previously built openssl
+ cd $(CURL) && PKG_CONFIG_PATH=$(DESTDIR)/usr/local/lib/pkgconfig ./configure \
+ --enable-static \
+ --enable-shared \
+ --with-pic \
+ --enable-ipv6 \
+ --enable-versioned-symbols \
+ --enable-threaded-resolver \
+ --with-random=/dev/urandom \
+ --with-ca-bundle=/etc/ssl/certs/ca-certificates.crt \
+ --disable-ldap \
+ --disable-ldaps \
+ --disable-manual \
+ --disable-rtsp \
+ --disable-dict \
+ --disable-telnet \
+ --disable-pop3 \
+ --disable-imap \
+ --disable-smb \
+ --disable-smtp \
+ --disable-gopher \
+ --disable-crypto-auth \
+ --without-gssapi \
+ --without-libpsl \
+ --without-libidn2 \
+ --without-gnutls \
+ --without-polarssl \
+ --without-mbedtls \
+ --without-cyassl \
+ --without-nss \
+ --without-axtls \
+ --without-brotli \
+ --without-libmetalink \
+ --without-libssh \
+ --without-libssh2 \
+ --without-librtmp \
+ --without-nghttp2 \
+ --without-zsh-functions-dir
+ $(MAKE) -C $(CURL) -j$(NPROC)
+ $(MAKE) -C $(CURL) install DESTDIR=$(DESTDIR)
+
+$(CURL).tar.gz:
+ curl -L -o $@ https://curl.haxx.se/download/$@
+
+
+clean:
+ rm -rf $(BOOST) $(BOOST).tar.gz $(TBB) $(TBB).tar.gz $(OPENSSL) $(OPENSSL).tar.gz $(CURL) $(CURL).tar.gz
diff --git a/doc/deps-build/windows/slic3r-makedeps.ps1 b/doc/deps-build/windows/slic3r-makedeps.ps1
new file mode 100644
index 000000000..8b39cae30
--- /dev/null
+++ b/doc/deps-build/windows/slic3r-makedeps.ps1
@@ -0,0 +1,141 @@
+#!powershell
+#
+# This script downloads, configures and builds Slic3r PE dependencies for Unix.
+# (That is, all dependencies except perl + wxWidgets.)
+#
+# To use this script, launch the Visual Studio command line,
+# `cd` into the directory containing this script and use this command:
+#
+# powershell .\slic3r-makedeps.ps1
+#
+# The dependencies will be downloaded and unpacked into the current dir.
+# This script WILL NOT try to guess the build architecture (64 vs 32 bits),
+# it will by default build the 64-bit variant. To build the 32-bit variant, use:
+#
+# powershell .\slic3r-makedeps.ps1 -b32
+#
+# Built libraries are installed into $destdir,
+# which by default is C:\local\slic3r-destdir-$bits
+# You can customize the $destdir using:
+#
+# powershell .\slic3r-makedeps.ps1 -destdir C:\foo\bar
+#
+# To pass the $destdir path along to cmake, set the use CMAKE_PREFIX_PATH variable
+# and set it to $destdir\usr\local
+#
+# Script requirements: PowerShell 3.0, .NET 4.5
+#
+
+
+param(
+ [switch]$b32 = $false,
+ [string]$destdir = ""
+)
+
+if ($destdir -eq "") {
+ $destdir = "C:\local\slic3r-destdir-" + ('32', '64')[!$b32]
+}
+
+$BOOST = 'boost_1_63_0'
+$CURL = 'curl-7.28.0'
+$TBB_SHA = 'a0dc9bf76d0120f917b641ed095360448cabc85b'
+$TBB = "tbb-$TBB_SHA"
+
+
+try
+{
+
+
+# Set up various settings and utilities:
+[Environment]::CurrentDirectory = Get-Location
+$NPROC = (Get-WmiObject -class Win32_processor).NumberOfLogicalProcessors
+Add-Type -A System.IO.Compression.FileSystem
+# This fxies SSL/TLS errors, credit goes to Ansible; see their `win_get_url.ps1` file
+$security_protcols = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::SystemDefault
+if ([Net.SecurityProtocolType].GetMember('Tls11').Count -gt 0) {
+ $security_protcols = $security_protcols -bor [Net.SecurityProtocolType]::Tls11
+}
+if ([Net.SecurityProtocolType].GetMember('Tls12').Count -gt 0) {
+ $security_protcols = $security_protcols -bor [Net.SecurityProtocolType]::Tls12
+}
+[Net.ServicePointManager]::SecurityProtocol = $security_protcols
+$webclient = New-Object System.Net.WebClient
+
+
+# Ensure DESTDIR exists:
+mkdir $destdir -ea 0
+mkdir "$destdir\usr\local" -ea 0
+
+
+# Download sources:
+echo 'Downloading sources ...'
+if (!(Test-Path "$BOOST.zip")) { $webclient.DownloadFile("https://dl.bintray.com/boostorg/release/1.63.0/source/$BOOST.zip", "$BOOST.zip") }
+if (!(Test-Path "$TBB.zip")) { $webclient.DownloadFile("https://github.com/wjakob/tbb/archive/$TBB_SHA.zip", "$TBB.zip") }
+if (!(Test-Path "$CURL.zip")) { $webclient.DownloadFile("https://curl.haxx.se/download/$CURL.zip", ".\$CURL.zip") }
+
+
+# Unpack sources:
+echo 'Unpacking ...'
+if (!(Test-Path $BOOST)) { [IO.Compression.ZipFile]::ExtractToDirectory("$BOOST.zip", '.') }
+if (!(Test-Path $TBB)) { [IO.Compression.ZipFile]::ExtractToDirectory("$TBB.zip", '.') }
+if (!(Test-Path $CURL)) { [IO.Compression.ZipFile]::ExtractToDirectory("$CURL.zip", '.') }
+
+
+# Build libraries:
+echo 'Building ...'
+
+# Build boost
+pushd "$BOOST"
+.\bootstrap
+$adr_mode = ('32', '64')[!$b32]
+.\b2 `
+ -j "$NPROC" `
+ --with-system `
+ --with-filesystem `
+ --with-thread `
+ --with-log `
+ --with-locale `
+ --with-regex `
+ "--prefix=$destdir/usr/local" `
+ "address-model=$adr_mode" `
+ toolset=msvc-12.0 `
+ link=static `
+ variant=release `
+ threading=multi `
+ boost.locale.icu=off `
+ install
+popd
+
+# Build TBB
+pushd "$TBB"
+mkdir 'mybuild' -ea 0
+cd 'mybuild'
+$generator = ('Visual Studio 12', 'Visual Studio 12 Win64')[!$b32]
+cmake .. `
+ -G "$generator" `
+ -DCMAKE_CONFIGURATION_TYPES=Release `
+ -DTBB_BUILD_SHARED=OFF `
+ -DTBB_BUILD_TESTS=OFF "-DCMAKE_INSTALL_PREFIX:PATH=$destdir\usr\local"
+msbuild /P:Configuration=Release INSTALL.vcxproj
+popd
+
+# Build libcurl:
+pushd "$CURL\winbuild"
+$machine = ("x86", "x64")[!$b32]
+nmake /f Makefile.vc mode=static VC=12 GEN_PDB=yes DEBUG=no "MACHINE=$machine"
+Copy-Item -R -Force ..\builds\libcurl-*-winssl\include\* "$destdir\usr\local\include\"
+Copy-Item -R -Force ..\builds\libcurl-*-winssl\lib\* "$destdir\usr\local\lib\"
+popd
+
+
+echo ""
+echo "All done!"
+echo ""
+
+
+}
+catch [Exception]
+{
+ # This prints errors in a verbose manner
+ echo $_.Exception|format-list -force
+}
diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt
index 35d1fc7de..93c70d051 100644
--- a/xs/CMakeLists.txt
+++ b/xs/CMakeLists.txt
@@ -199,6 +199,8 @@ add_library(libslic3r_gui STATIC
${LIBDIR}/slic3r/GUI/2DBed.hpp
${LIBDIR}/slic3r/GUI/wxExtensions.cpp
${LIBDIR}/slic3r/GUI/wxExtensions.hpp
+ ${LIBDIR}/slic3r/Utils/Http.cpp
+ ${LIBDIR}/slic3r/Utils/Http.hpp
)
add_library(admesh STATIC
@@ -523,6 +525,20 @@ if (SLIC3R_PRUSACONTROL)
target_link_libraries(XS ${wxWidgets_LIBRARIES})
endif()
+find_package(CURL REQUIRED)
+include_directories(${CURL_INCLUDE_DIRS})
+target_link_libraries(XS ${CURL_LIBRARIES})
+
+if (SLIC3R_STATIC AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ # As of now, our build system produces a statically linked libcurl,
+ # which links the OpenSSL library dynamically.
+ find_package(OpenSSL REQUIRED)
+ message("OpenSSL include dir: ${OPENSSL_INCLUDE_DIR}")
+ message("OpenSSL libraries: ${OPENSSL_LIBRARIES}")
+ include_directories(${OPENSSL_INCLUDE_DIR})
+ target_link_libraries(XS ${OPENSSL_LIBRARIES})
+endif()
+
## OPTIONAL packages
# Find eigen3 or use bundled version
@@ -597,6 +613,17 @@ elseif (NOT MSVC)
target_link_libraries(slic3r -lstdc++)
endif ()
+if (MSVC)
+ # Here we associate some additional properties with the MSVC projects to enable compilation and debugging out of the box.
+ # It seems a props file needs to be copied to the same dir as the proj file, otherwise MSVC doesn't load it up.
+ # For copying, the configure_file() function seems to work much better than the file() function.
+ configure_file("${PROJECT_SOURCE_DIR}/cmake/msvc/xs.wperl64d.props" ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
+ set_target_properties(XS PROPERTIES VS_USER_PROPS "xs.wperl64d.props")
+ configure_file("${PROJECT_SOURCE_DIR}/cmake/msvc/slic3r.wperl64d.props" ${CMAKE_CURRENT_BINARY_DIR} COPYONLY)
+ set_target_properties(slic3r PROPERTIES VS_USER_PROPS "slic3r.wperl64d.props")
+endif ()
+
+
# Installation
-install(TARGETS XS DESTINATION lib/slic3r-prusa3d/auto/Slic3r/XS)
-install(FILES lib/Slic3r/XS.pm DESTINATION lib/slic3r-prusa3d/Slic3r)
+install(TARGETS XS DESTINATION ${PERL_VENDORARCH}/auto/Slic3r/XS)
+install(FILES lib/Slic3r/XS.pm DESTINATION ${PERL_VENDORLIB}/Slic3r)
diff --git a/xs/src/slic3r/Utils/Http.cpp b/xs/src/slic3r/Utils/Http.cpp
new file mode 100644
index 000000000..45a350a59
--- /dev/null
+++ b/xs/src/slic3r/Utils/Http.cpp
@@ -0,0 +1,261 @@
+#include "Http.hpp"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include "../../libslic3r/libslic3r.h"
+
+
+namespace Slic3r {
+
+
+// Private
+
+class CurlGlobalInit
+{
+ static const CurlGlobalInit instance;
+
+ CurlGlobalInit() { ::curl_global_init(CURL_GLOBAL_DEFAULT); }
+ ~CurlGlobalInit() { ::curl_global_cleanup(); }
+};
+
+struct Http::priv
+{
+ enum {
+ DEFAULT_SIZE_LIMIT = 5 * 1024 * 1024,
+ };
+
+ ::CURL *curl;
+ ::curl_httppost *form;
+ ::curl_httppost *form_end;
+ ::curl_slist *headerlist;
+ std::string buffer;
+ size_t limit;
+
+ std::thread io_thread;
+ Http::CompleteFn completefn;
+ Http::ErrorFn errorfn;
+
+ priv(const std::string &url);
+ ~priv();
+
+ static size_t writecb(void *data, size_t size, size_t nmemb, void *userp);
+ std::string body_size_error();
+ void http_perform();
+};
+
+Http::priv::priv(const std::string &url) :
+ curl(::curl_easy_init()),
+ form(nullptr),
+ form_end(nullptr),
+ headerlist(nullptr)
+{
+ if (curl == nullptr) {
+ throw std::runtime_error(std::string("Could not construct Curl object"));
+ }
+
+ ::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally
+ ::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_FORK_NAME "/" SLIC3R_VERSION);
+}
+
+Http::priv::~priv()
+{
+ ::curl_easy_cleanup(curl);
+ ::curl_formfree(form);
+ ::curl_slist_free_all(headerlist);
+}
+
+size_t Http::priv::writecb(void *data, size_t size, size_t nmemb, void *userp)
+{
+ auto self = static_cast(userp);
+ const char *cdata = static_cast(data);
+ const size_t realsize = size * nmemb;
+
+ const size_t limit = self->limit > 0 ? self->limit : DEFAULT_SIZE_LIMIT;
+ if (self->buffer.size() + realsize > limit) {
+ // This makes curl_easy_perform return CURLE_WRITE_ERROR
+ return 0;
+ }
+
+ self->buffer.append(cdata, realsize);
+
+ return realsize;
+}
+
+std::string Http::priv::body_size_error()
+{
+ return (boost::format("HTTP body data size exceeded limit (%1% bytes)") % limit).str();
+}
+
+void Http::priv::http_perform()
+{
+ ::curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
+ ::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
+ ::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb);
+ ::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast(this));
+
+#ifndef NDEBUG
+ ::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+#endif
+
+ if (headerlist != nullptr) {
+ ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
+ }
+
+ if (form != nullptr) {
+ ::curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
+ }
+
+ CURLcode res = ::curl_easy_perform(curl);
+ long http_status = 0;
+ ::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
+
+ if (res != CURLE_OK) {
+ std::string error;
+ if (res == CURLE_WRITE_ERROR) {
+ error = std::move(body_size_error());
+ } else {
+ error = ::curl_easy_strerror(res);
+ };
+
+ if (errorfn) {
+ errorfn(std::move(buffer), std::move(error), http_status);
+ }
+ } else {
+ if (completefn) {
+ completefn(std::move(buffer), http_status);
+ }
+ }
+}
+
+Http::Http(const std::string &url) : p(new priv(url)) {}
+
+
+// Public
+
+Http::Http(Http &&other) : p(std::move(other.p)) {}
+
+Http::~Http()
+{
+ if (p && p->io_thread.joinable()) {
+ p->io_thread.detach();
+ }
+}
+
+
+Http& Http::size_limit(size_t sizeLimit)
+{
+ if (p) { p->limit = sizeLimit; }
+ return *this;
+}
+
+Http& Http::header(std::string name, const std::string &value)
+{
+ if (!p) { return * this; }
+
+ if (name.size() > 0) {
+ name.append(": ").append(value);
+ } else {
+ name.push_back(':');
+ }
+ p->headerlist = curl_slist_append(p->headerlist, name.c_str());
+ return *this;
+}
+
+Http& Http::remove_header(std::string name)
+{
+ if (p) {
+ name.push_back(':');
+ p->headerlist = curl_slist_append(p->headerlist, name.c_str());
+ }
+
+ return *this;
+}
+
+Http& Http::ca_file(const std::string &name)
+{
+ if (p) {
+ ::curl_easy_setopt(p->curl, CURLOPT_CAINFO, name.c_str());
+ }
+
+ return *this;
+}
+
+Http& Http::form_add(const std::string &name, const std::string &contents)
+{
+ if (p) {
+ ::curl_formadd(&p->form, &p->form_end,
+ CURLFORM_COPYNAME, name.c_str(),
+ CURLFORM_COPYCONTENTS, contents.c_str(),
+ CURLFORM_END
+ );
+ }
+
+ return *this;
+}
+
+Http& Http::form_add_file(const std::string &name, const std::string &filename)
+{
+ if (p) {
+ ::curl_formadd(&p->form, &p->form_end,
+ CURLFORM_COPYNAME, name.c_str(),
+ CURLFORM_FILE, filename.c_str(),
+ CURLFORM_CONTENTTYPE, "application/octet-stream",
+ CURLFORM_END
+ );
+ }
+
+ return *this;
+}
+
+Http& Http::on_complete(CompleteFn fn)
+{
+ if (p) { p->completefn = std::move(fn); }
+ return *this;
+}
+
+Http& Http::on_error(ErrorFn fn)
+{
+ if (p) { p->errorfn = std::move(fn); }
+ return *this;
+}
+
+Http::Ptr Http::perform()
+{
+ auto self = std::make_shared(std::move(*this));
+
+ if (self->p) {
+ auto io_thread = std::thread([self](){
+ self->p->http_perform();
+ });
+ self->p->io_thread = std::move(io_thread);
+ }
+
+ return self;
+}
+
+void Http::perform_sync()
+{
+ if (p) { p->http_perform(); }
+}
+
+Http Http::get(std::string url)
+{
+ return std::move(Http{std::move(url)});
+}
+
+Http Http::post(std::string url)
+{
+ Http http{std::move(url)};
+ curl_easy_setopt(http.p->curl, CURLOPT_POST, 1L);
+ return http;
+}
+
+
+}
diff --git a/xs/src/slic3r/Utils/Http.hpp b/xs/src/slic3r/Utils/Http.hpp
new file mode 100644
index 000000000..c591e17c5
--- /dev/null
+++ b/xs/src/slic3r/Utils/Http.hpp
@@ -0,0 +1,53 @@
+#ifndef slic3r_Http_hpp_
+#define slic3r_Http_hpp_
+
+#include
+#include
+#include
+
+
+namespace Slic3r {
+
+
+/// Represetns a Http request
+class Http : public std::enable_shared_from_this {
+private:
+ struct priv;
+public:
+ typedef std::shared_ptr Ptr;
+ typedef std::function CompleteFn;
+ typedef std::function ErrorFn;
+
+ Http(Http &&other);
+
+ static Http get(std::string url);
+ static Http post(std::string url);
+ ~Http();
+
+ Http(const Http &) = delete;
+ Http& operator=(const Http &) = delete;
+ Http& operator=(Http &&) = delete;
+
+ Http& size_limit(size_t sizeLimit);
+ Http& header(std::string name, const std::string &value);
+ Http& remove_header(std::string name);
+ Http& ca_file(const std::string &filename);
+ Http& form_add(const std::string &name, const std::string &contents);
+ Http& form_add_file(const std::string &name, const std::string &filename);
+
+ Http& on_complete(CompleteFn fn);
+ Http& on_error(ErrorFn fn);
+
+ Ptr perform();
+ void perform_sync();
+
+private:
+ Http(const std::string &url);
+
+ std::unique_ptr p;
+};
+
+
+}
+
+#endif
diff --git a/xs/src/xsinit.h b/xs/src/xsinit.h
index 49981b74b..96c4b74d7 100644
--- a/xs/src/xsinit.h
+++ b/xs/src/xsinit.h
@@ -59,6 +59,15 @@ extern "C" {
#undef seek
#undef send
#undef write
+ #undef open
+ #undef close
+ #undef seekdir
+ #undef setbuf
+ #undef fread
+ #undef fseek
+ #undef fputc
+ #undef fwrite
+ #undef fclose
#endif /* _MSC_VER */
}
#endif