aboutsummaryrefslogtreecommitdiff
path: root/butl/curl.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-04-18 10:40:18 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-04-18 10:40:18 +0200
commited93e07b1b7a9e0ba99609a9223e43247ff4224e (patch)
treeaa203bdab5a5fc4f5fd8af16baf6903a7ee3dde0 /butl/curl.cxx
parent4408607c51a7c6e293adae41403b21d4a2c9a429 (diff)
Implement curl process
Diffstat (limited to 'butl/curl.cxx')
-rw-r--r--butl/curl.cxx166
1 files changed, 166 insertions, 0 deletions
diff --git a/butl/curl.cxx b/butl/curl.cxx
new file mode 100644
index 0000000..4951b52
--- /dev/null
+++ b/butl/curl.cxx
@@ -0,0 +1,166 @@
+// file : butl/curl.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#include <butl/curl>
+
+#include <utility> // move(), forward()
+#include <exception> // invalid_argument
+
+#include <butl/utility> // casecmp()
+
+using namespace std;
+
+namespace butl
+{
+ int curl::
+ map_in (nullfd_t, method_proto mp, io_data& d)
+ {
+ switch (mp)
+ {
+ case ftp_put:
+ throw invalid_argument ("no input specified for PUT method");
+ case http_post:
+ throw invalid_argument ("no input specified for POST method");
+ case ftp_get:
+ case http_get:
+ {
+ d.pipe.in.reset (fdnull ()); // /dev/null
+ return d.pipe.in.get ();
+ }
+ }
+
+ return -1;
+ }
+
+ int curl::
+ map_in (const path& f, method_proto mp, io_data& d)
+ {
+ switch (mp)
+ {
+ case ftp_put:
+ case http_post:
+ {
+ if (mp == ftp_put)
+ {
+ d.options.push_back ("--upload-file");
+ d.options.push_back (f.string ().c_str ());
+ }
+ else
+ {
+ d.storage = '@' + f.string ();
+
+ d.options.push_back ("--data-binary");
+ d.options.push_back (d.storage.c_str ());
+ }
+
+ if (f.string () == "-")
+ {
+ d.pipe = fdopen_pipe (fdopen_mode::binary);
+ out.open (move (d.pipe.out));
+ }
+ else
+ d.pipe.in.reset (fdnull ()); // /dev/null
+
+ return d.pipe.in.get ();
+ }
+ case ftp_get:
+ case http_get:
+ {
+ throw invalid_argument ("file input specified for GET method");
+ }
+ }
+
+ return -1;
+ }
+
+ int curl::
+ map_out (nullfd_t, method_proto mp, io_data& d)
+ {
+ switch (mp)
+ {
+ case ftp_get:
+ case http_get:
+ throw invalid_argument ("no output specified for GET method");
+ case ftp_put:
+ case http_post: // May or may not produce output.
+ {
+ d.pipe.out.reset (fdnull ());
+ return d.pipe.out.get (); // /dev/null
+ }
+ }
+
+ return -1;
+ }
+
+ int curl::
+ map_out (const path& f, method_proto mp, io_data& d)
+ {
+ switch (mp)
+ {
+ case ftp_get:
+ case http_get:
+ case http_post:
+ {
+ if (f.string () == "-")
+ {
+ // Note: no need for any options, curl writes to stdout by default.
+ //
+ d.pipe = fdopen_pipe (fdopen_mode::binary);
+ in.open (move (d.pipe.in));
+ }
+ else
+ {
+ d.options.push_back ("-o");
+ d.options.push_back (f.string ().c_str ());
+ d.pipe.out.reset (fdnull ()); // /dev/null
+ }
+
+ return d.pipe.out.get ();
+ }
+ case ftp_put:
+ {
+ throw invalid_argument ("file output specified for PUT method");
+ }
+ }
+
+ return -1;
+ }
+
+ curl::method_proto curl::
+ translate (method_type m, const string& u, method_proto_options& o)
+ {
+ size_t n (u.find ("://"));
+
+ if (n == string::npos)
+ throw invalid_argument ("no protocol in URL");
+
+ if (casecmp (u, "ftp", n) == 0 ||
+ casecmp (u, "tftp", n) == 0)
+ {
+ switch (m)
+ {
+ case method_type::get: return method_proto::ftp_get;
+ case method_type::put: return method_proto::ftp_put;
+ case method_type::post:
+ throw invalid_argument ("POST method with FTP protocol");
+ }
+ }
+ else if (casecmp (u, "http", n) == 0 ||
+ casecmp (u, "https", n) == 0)
+ {
+ o.push_back ("--fail"); // Fail on HTTP errors (e.g., 404).
+ o.push_back ("--location"); // Follow redirects.
+
+ switch (m)
+ {
+ case method_type::get: return method_proto::http_get;
+ case method_type::post: return method_proto::http_post;
+ case method_type::put:
+ throw invalid_argument ("PUT method with HTTP protocol");
+ }
+ }
+
+ throw invalid_argument ("unsupported protocol");
+ }
+}