Browse Source

connect_for() for opening connections based on URLs

default_compile_flags
vector-of-bool 4 years ago
parent
commit
850d02e379
3 changed files with 51 additions and 3 deletions
  1. +1
    -3
      src/dds/catalog/remote/http.cpp
  2. +35
    -0
      src/dds/http/session.cpp
  3. +15
    -0
      src/dds/http/session.hpp

+ 1
- 3
src/dds/catalog/remote/http.cpp View File



void http_download_with_redir(neo::url url, path_ref dest) { void http_download_with_redir(neo::url url, path_ref dest) {
for (auto redir_count = 0;; ++redir_count) { for (auto redir_count = 0;; ++redir_count) {
auto sess = url.scheme == "https"
? http_session::connect_ssl(*url.host, url.port_or_default_port_or(443))
: http_session::connect(*url.host, url.port_or_default_port_or(80));
auto sess = http_session::connect_for(url);


sess.send_head({.method = "GET", .path = url.path}); sess.send_head({.method = "GET", .path = url.path});



+ 35
- 0
src/dds/http/session.cpp View File



#include <fmt/format.h> #include <fmt/format.h>
#include <fmt/ostream.h> #include <fmt/ostream.h>
#include <neo/event.hpp>
#include <neo/http/parse/chunked.hpp> #include <neo/http/parse/chunked.hpp>
#include <neo/http/request.hpp> #include <neo/http/request.hpp>
#include <neo/http/response.hpp> #include <neo/http/response.hpp>


} // namespace } // namespace


http_session http_session::connect_for(const neo::url& url) {
if (!url.host) {
throw_user_error<
errc::invalid_remote_url>("URL is invalid for network connection [{}]: No host segment",
url.to_string());
}
auto sub = neo::subscribe(
[&](neo::address::ev_resolve ev) {
dds_log(trace, "Resolving '{}:{}'", ev.host, ev.service);
neo::bubble_event(ev);
},
[&](neo::socket::ev_connect ev) {
dds_log(trace, "Connecting {}", *url.host);
neo::bubble_event(ev);
},
[&](neo::ssl::ev_handshake ev) {
dds_log(trace, "TLS handshake...");
neo::bubble_event(ev);
});
if (url.scheme == "http") {
return connect(*url.host, url.port_or_default_port_or(80));
} else if (url.scheme == "https") {
return connect_ssl(*url.host, url.port_or_default_port_or(443));
} else {
throw_user_error<errc::invalid_remote_url>("URL is invalid [{}]", url.to_string());
}
}

http_session http_session::connect(const std::string& host, int port) { http_session http_session::connect(const std::string& host, int port) {
DDS_E_SCOPE(e_http_connect{host, port}); DDS_E_SCOPE(e_http_connect{host, port});


params.method, params.method,
params.path, params.path,
params.query); params.query);
neo::emit(ev_http_request{params});
neo::http::request_line start_line{ neo::http::request_line start_line{
.method_view = params.method, .method_view = params.method,
.target = neo::http::origin_form_target{ .target = neo::http::origin_form_target{


auto cl_str = std::to_string(params.content_length); auto cl_str = std::to_string(params.content_length);


// TODO: GZip downloads
std::pair<std::string_view, std::string_view> headers[] = { std::pair<std::string_view, std::string_view> headers[] = {
{"Host", host_string()}, {"Host", host_string()},
{"Accept", "*/*"}, {"Accept", "*/*"},
= _do_io([&](auto&& io) { return neo::http::read_response_head<http_response_info>(io); }); = _do_io([&](auto&& io) { return neo::http::read_response_head<http_response_info>(io); });
dds_log(trace, "Recv: HTTP {} {}", r.status, r.status_message); dds_log(trace, "Recv: HTTP {} {}", r.status, r.status_message);
_state = _state_t::recvd_head; _state = _state_t::recvd_head;
neo::emit(ev_http_response_begin{r});
return r; return r;
} }




neo::string_dynbuf_io resp_body; neo::string_dynbuf_io resp_body;
_do_io([&](auto&& io) { download_into(resp_body, io, resp_head); }); _do_io([&](auto&& io) { download_into(resp_body, io, resp_head); });
neo::emit(ev_http_response_end{resp_head});
auto body_size = resp_body.available(); auto body_size = resp_body.available();
auto str = std::move(resp_body.string()); auto str = std::move(resp_body.string());
str.resize(body_size); str.resize(body_size);
_state = _state_t::ready;
return str; return str;
} }


auto ofile = neo::file_stream::open(dest, neo::open_mode::write | neo::open_mode::create); auto ofile = neo::file_stream::open(dest, neo::open_mode::write | neo::open_mode::create);
neo::stream_io_buffers file_out{ofile}; neo::stream_io_buffers file_out{ofile};
_do_io([&](auto&& io) { download_into(file_out, io, resp_head); }); _do_io([&](auto&& io) { download_into(file_out, io, resp_head); });
neo::emit(ev_http_response_end{resp_head});
_state = _state_t::ready; _state = _state_t::ready;
} }



+ 15
- 0
src/dds/http/session.hpp View File

#include <neo/io/stream/buffers.hpp> #include <neo/io/stream/buffers.hpp>
#include <neo/io/stream/socket.hpp> #include <neo/io/stream/socket.hpp>
#include <neo/string_io.hpp> #include <neo/string_io.hpp>
#include <neo/url.hpp>


#include <filesystem> #include <filesystem>
#include <string> #include <string>
std::size_t content_length = 0; std::size_t content_length = 0;
}; };


struct ev_http_request {
const http_request_params& request;
};

struct http_response_info { struct http_response_info {
int status; int status;
std::string status_message; std::string status_message;
bool is_redirect() const noexcept { return status >= 300 && status < 400; } bool is_redirect() const noexcept { return status >= 300 && status < 400; }
}; };


struct ev_http_response_begin {
const http_response_info& response;
};

struct ev_http_response_end {
const http_response_info& response;
};

enum class http_kind { enum class http_kind {
plain, plain,
ssl, ssl,
static http_session connect(const std::string& host, int port); static http_session connect(const std::string& host, int port);
static http_session connect_ssl(const std::string& host, int port); static http_session connect_ssl(const std::string& host, int port);


static http_session connect_for(const neo::url& url);

std::string request(http_request_params); std::string request(http_request_params);


std::string request_get(std::string_view path) { std::string request_get(std::string_view path) {

Loading…
Cancel
Save