Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbubnikv <bubnikv@gmail.com>2018-03-06 12:15:17 +0300
committerbubnikv <bubnikv@gmail.com>2018-03-06 12:15:17 +0300
commit51da42734ade81cc789ae9862993771856f6a9dc (patch)
tree5ac284d7bedd7749139727d585b5565bf04e98f9 /xs/src/slic3r
parent3c64eb9215cc6d285571866062d933035d435eb6 (diff)
parent79ee7c9a36b4901804e87ecb17dd6821a23ba258 (diff)
Merge remote-tracking branch 'origin/http+build'
Diffstat (limited to 'xs/src/slic3r')
-rw-r--r--xs/src/slic3r/Utils/Http.cpp261
-rw-r--r--xs/src/slic3r/Utils/Http.hpp53
2 files changed, 314 insertions, 0 deletions
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 <cstdlib>
+#include <functional>
+#include <thread>
+#include <iostream>
+#include <tuple>
+#include <boost/format.hpp>
+
+#include <curl/curl.h>
+
+#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<priv*>(userp);
+ const char *cdata = static_cast<char*>(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<void*>(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<Http>(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 <memory>
+#include <string>
+#include <functional>
+
+
+namespace Slic3r {
+
+
+/// Represetns a Http request
+class Http : public std::enable_shared_from_this<Http> {
+private:
+ struct priv;
+public:
+ typedef std::shared_ptr<Http> Ptr;
+ typedef std::function<void(std::string /* body */, unsigned /* http_status */)> CompleteFn;
+ typedef std::function<void(std::string /* body */, std::string /* error */, unsigned /* http_status */)> 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<priv> p;
+};
+
+
+}
+
+#endif