aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils/http_get
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils/http_get')
-rw-r--r--src/utils/http_get/http_get.cpp95
-rw-r--r--src/utils/http_get/http_get.h34
-rw-r--r--src/utils/http_get/info.txt3
3 files changed, 132 insertions, 0 deletions
diff --git a/src/utils/http_get/http_get.cpp b/src/utils/http_get/http_get.cpp
new file mode 100644
index 000000000..a6069c861
--- /dev/null
+++ b/src/utils/http_get/http_get.cpp
@@ -0,0 +1,95 @@
+/*
+* HTTP GET function
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/http_get.h>
+#include <botan/parsing.h>
+#include <boost/asio.hpp>
+
+namespace Botan {
+
+http_response sync_http_get(const std::string& url, std::chrono::milliseconds timeout)
+ {
+ using namespace boost::asio::ip;
+
+ const auto protocol_host_sep = url.find("://");
+ const auto host_loc_sep = url.find('/', protocol_host_sep + 3);
+
+ if(protocol_host_sep == std::string::npos || host_loc_sep == std::string::npos)
+ throw std::runtime_error("Invalid URL " + url);
+
+ const std::string protocol = url.substr(0, protocol_host_sep);
+ const std::string hostname = url.substr(protocol_host_sep+3, host_loc_sep-protocol_host_sep-3);
+ const std::string loc = url.substr(host_loc_sep, std::string::npos);
+
+ if(protocol != "http")
+ throw std::runtime_error("Unsupported protocol " + protocol);
+
+ tcp::iostream sock;
+
+ if(timeout.count())
+ sock.expires_from_now(boost::posix_time::milliseconds(timeout.count()));
+
+ sock.connect(hostname, protocol);
+ if(!sock)
+ throw std::runtime_error("Connection to " + hostname + " / " + protocol + " failed");
+
+ sock << "GET " << loc << " HTTP/1.0\r\n";
+ sock << "Host: " << hostname << "\r\n";
+ sock << "Accept: */*\r\n";
+ sock << "Cache-Control: no-cache\r\n";
+ sock << "Connection: close\r\n\r\n";
+ sock.flush();
+
+ std::string line1;
+ std::getline(sock, line1);
+ if(!sock)
+ throw std::runtime_error("No response");
+
+ std::stringstream response_stream(line1);
+ std::string http_version;
+ unsigned int status_code;
+ std::string status_message;
+
+ response_stream >> http_version >> status_code;
+
+ std::getline(response_stream, status_message);
+
+ if(!response_stream || http_version.substr(0,5) != "HTTP/")
+ throw std::runtime_error("Not an HTTP response");
+
+ std::map<std::string, std::string> headers;
+ std::string header_line;
+ while (std::getline(sock, header_line) && header_line != "\r")
+ {
+ auto sep = header_line.find(": ");
+ if(sep == std::string::npos || sep > header_line.size() - 2)
+ throw std::runtime_error("Invalid HTTP header " + header_line);
+ const std::string key = header_line.substr(0, sep);
+ const std::string val = header_line.substr(sep + 2, std::string::npos);
+ headers[key] = val;
+ }
+
+ if(status_code == 301 && headers.count("Location"))
+ return sync_http_get(headers["Location"], timeout);
+
+ std::vector<byte> body;
+ std::vector<byte> buf(4096);
+ while(sock.good())
+ {
+ sock.read(reinterpret_cast<char*>(&buf[0]), buf.size());
+ body.insert(body.end(), &buf[0], &buf[sock.gcount()]);
+ }
+
+ return http_response { status_code, body, headers };
+ }
+
+std::future<http_response> async_http_get(const std::string& url)
+ {
+ return std::async(std::launch::async, sync_http_get, url, std::chrono::seconds(3));
+ }
+
+}
diff --git a/src/utils/http_get/http_get.h b/src/utils/http_get/http_get.h
new file mode 100644
index 000000000..68ee2f85c
--- /dev/null
+++ b/src/utils/http_get/http_get.h
@@ -0,0 +1,34 @@
+/*
+* HTTP GET function
+* (C) 2013 Jack Lloyd
+*
+* Distributed under the terms of the Botan license
+*/
+
+#include <botan/types.h>
+#include <future>
+#include <vector>
+#include <map>
+#include <chrono>
+#include <string>
+
+#ifndef BOTAN_UTILS_URLGET_H__
+#define BOTAN_UTILS_URLGET_H__
+
+namespace Botan {
+
+struct http_response
+ {
+ unsigned int status_code;
+ std::vector<byte> body;
+ std::map<std::string, std::string> headers;
+ };
+
+BOTAN_DLL http_response sync_http_get(const std::string& url,
+ std::chrono::milliseconds timeout);
+
+BOTAN_DLL std::future<http_response> BOTAN_DLL async_http_get(const std::string& url);
+
+}
+
+#endif
diff --git a/src/utils/http_get/info.txt b/src/utils/http_get/info.txt
new file mode 100644
index 000000000..ab36a6b95
--- /dev/null
+++ b/src/utils/http_get/info.txt
@@ -0,0 +1,3 @@
+define HTTP_GET
+
+load_on auto