diff --git a/luprex/core/cpp/driver-ssl.cpp b/luprex/core/cpp/driver-ssl.cpp index a4b6ffa6..b793282c 100644 --- a/luprex/core/cpp/driver-ssl.cpp +++ b/luprex/core/cpp/driver-ssl.cpp @@ -82,7 +82,7 @@ std::string errors_string(bool lastonly) { } else { err = err + ", " + reason; } - if (data != nullptr) { + if ((data != nullptr) && (data[0] != 0)) { err = err + " " + data; } } diff --git a/luprex/core/cpp/http.cpp b/luprex/core/cpp/http.cpp index 5db07712..291de5e2 100644 --- a/luprex/core/cpp/http.cpp +++ b/luprex/core/cpp/http.cpp @@ -186,21 +186,21 @@ public: } }; -HttpOutRequest::HttpOutRequest() { - verify_certificate_ = true; +HttpClientRequest::HttpClientRequest() { + verify_certificate_ = false; port_ = 0; request_id_ = 0; place_id_ = 0; thread_id_ = 0; } -void HttpOutRequest::fail(string_view s) { +void HttpClientRequest::fail(string_view s) { if (error_.empty()) { error_ = s; } } -eng::string HttpOutRequest::target() const { +eng::string HttpClientRequest::target() const { assert(check().empty()); eng::ostringstream oss; oss << (verify_certificate_ ? "cert" : "nocert"); @@ -208,11 +208,11 @@ eng::string HttpOutRequest::target() const { return oss.str(); } -void HttpOutRequest::set_verify_certificate(bool flag) { +void HttpClientRequest::set_verify_certificate(bool flag) { verify_certificate_ = flag; } -void HttpOutRequest::set_method(const eng::string &s) { +void HttpClientRequest::set_method(const eng::string &s) { eng::string method = util::ascii_toupper(s); if ((method != "GET") && (method != "HEAD")) { fail(util::ss("HTTP method not implemented: ", method, ".", @@ -226,7 +226,7 @@ void HttpOutRequest::set_method(const eng::string &s) { method_ = method; } -void HttpOutRequest::set_host(const eng::string &s) { +void HttpClientRequest::set_host(const eng::string &s) { eng::string host = util::ascii_tolower(s); if (host.empty()) { fail(util::ss("HTTP hostname cannot be empty string.")); @@ -247,7 +247,7 @@ void HttpOutRequest::set_host(const eng::string &s) { host_ = host; } -void HttpOutRequest::set_port(int port) { +void HttpClientRequest::set_port(int port) { if ((port < 1) || (port > 65535)) { fail(util::ss("HTTP port must be between 1 and 65535: ", port)); return; @@ -259,7 +259,7 @@ void HttpOutRequest::set_port(int port) { port_ = port; } -void HttpOutRequest::set_path(string_view path) { +void HttpClientRequest::set_path(string_view path) { if (!sv::has_prefix(path, "/")) { fail(util::ss("HTTP path must start with slash")); return; @@ -271,7 +271,7 @@ void HttpOutRequest::set_path(string_view path) { path_ = path; } -void HttpOutRequest::set_param(const eng::string &key, const eng::string &val) { +void HttpClientRequest::set_param(const eng::string &key, const eng::string &val) { if (params_.find(key) != params_.end()) { fail(util::ss("HTTP url parameter specified twice: ", key)); return; @@ -283,7 +283,7 @@ void HttpOutRequest::set_param(const eng::string &key, const eng::string &val) { params_[key] = val; } -void HttpOutRequest::set_url(string_view url) { +void HttpClientRequest::set_url(string_view url) { ParsedURL parsed_url(url); if (!parsed_url.valid) { fail(util::ss("syntactically invalid URL: ", url)); @@ -301,7 +301,7 @@ void HttpOutRequest::set_url(string_view url) { } } -void HttpOutRequest::set_verify_certificate(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_verify_certificate(LuaStack &LS, LuaSlot val) { if (!LS.isboolean(val)) { fail(util::ss("HTTP verify_certificate must be a boolean")); return; @@ -309,7 +309,7 @@ void HttpOutRequest::set_verify_certificate(LuaStack &LS, LuaSlot val) { set_verify_certificate(LS.ckboolean(val)); } -void HttpOutRequest::set_method(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_method(LuaStack &LS, LuaSlot val) { if (!LS.isstring(val)) { fail(util::ss("HTTP method must be a string")); return; @@ -317,7 +317,7 @@ void HttpOutRequest::set_method(LuaStack &LS, LuaSlot val) { set_method(LS.ckstring(val)); } -void HttpOutRequest::set_host(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_host(LuaStack &LS, LuaSlot val) { if (!LS.isstring(val)) { fail(util::ss("HTTP host must be a string")); return; @@ -325,7 +325,7 @@ void HttpOutRequest::set_host(LuaStack &LS, LuaSlot val) { set_host(LS.ckstring(val)); } -void HttpOutRequest::set_port(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_port(LuaStack &LS, LuaSlot val) { if (!LS.isint(val)) { fail(util::ss("HTTP port must be an int")); return; @@ -333,7 +333,7 @@ void HttpOutRequest::set_port(LuaStack &LS, LuaSlot val) { set_port(LS.ckint(val)); } -void HttpOutRequest::set_path(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_path(LuaStack &LS, LuaSlot val) { if (!LS.isstring(val)) { fail(util::ss("HTTP path must be a string")); return; @@ -341,7 +341,7 @@ void HttpOutRequest::set_path(LuaStack &LS, LuaSlot val) { set_path(LS.ckstring(val)); } -void HttpOutRequest::set_param(LuaStack &LS, LuaSlot key, LuaSlot val) { +void HttpClientRequest::set_param(LuaStack &LS, LuaSlot key, LuaSlot val) { if (!LS.isstring(key)) { fail(util::ss("HTTP url parameter key must be a string")); return; @@ -353,7 +353,7 @@ void HttpOutRequest::set_param(LuaStack &LS, LuaSlot key, LuaSlot val) { set_param(LS.ckstring(key), LS.ckstring(val)); } -void HttpOutRequest::set_params(LuaStack &LS0, LuaSlot tab) { +void HttpClientRequest::set_params(LuaStack &LS0, LuaSlot tab) { if (!LS0.istable(tab)) { fail(util::ss("HTTP params must be a table")); return; @@ -366,7 +366,7 @@ void HttpOutRequest::set_params(LuaStack &LS0, LuaSlot tab) { } } -void HttpOutRequest::set_url(LuaStack &LS, LuaSlot val) { +void HttpClientRequest::set_url(LuaStack &LS, LuaSlot val) { if (!LS.isstring(val)) { fail(util::ss("HTTP url must be a string")); return; @@ -374,7 +374,7 @@ void HttpOutRequest::set_url(LuaStack &LS, LuaSlot val) { set_url(LS.ckstring(val)); } -void HttpOutRequest::set_defaults() { +void HttpClientRequest::set_defaults() { if (method_.empty()) { method_ = "GET"; } @@ -383,7 +383,7 @@ void HttpOutRequest::set_defaults() { } } -void HttpOutRequest::set_config(LuaStack &LS0, LuaSlot tab) { +void HttpClientRequest::set_config(LuaStack &LS0, LuaSlot tab) { LuaVar key, val; LuaStack LS(LS0.state(), key, val); LS.set(key, LuaNil); @@ -412,7 +412,7 @@ void HttpOutRequest::set_config(LuaStack &LS0, LuaSlot tab) { } } -eng::string HttpOutRequest::check() const { +eng::string HttpClientRequest::check() const { if (!error_.empty()) { return error_; } @@ -432,7 +432,7 @@ eng::string HttpOutRequest::check() const { } -void HttpOutRequest::send_internal(StreamBuffer *sb, bool debug_string) const { +void HttpClientRequest::send_internal(StreamBuffer *sb, bool debug_string) const { // If there's an error in the request, handle it. In debug string mode, // we just put the error into the output. In production mode, we assert // fail. @@ -484,7 +484,7 @@ void HttpOutRequest::send_internal(StreamBuffer *sb, bool debug_string) const { } } -void HttpOutRequest::serialize(StreamBuffer *sb) const { +void HttpClientRequest::serialize(StreamBuffer *sb) const { sb->write_int64(request_id_); sb->write_int64(place_id_); sb->write_int64(thread_id_); @@ -501,7 +501,7 @@ void HttpOutRequest::serialize(StreamBuffer *sb) const { } } -void HttpOutRequest::deserialize(StreamBuffer *sb) { +void HttpClientRequest::deserialize(StreamBuffer *sb) { request_id_ = sb->read_int64(); place_id_ = sb->read_int64(); thread_id_ = sb->read_int64(); @@ -520,39 +520,40 @@ void HttpOutRequest::deserialize(StreamBuffer *sb) { } } -eng::string HttpOutRequest::DebugString() { +eng::string HttpClientRequest::DebugString() { StreamBuffer sb; send_internal(&sb, true); return eng::string(sb.view()); } -void HttpOutRequestMap::serialize(StreamBuffer *sb) const { +void HttpClientRequestMap::serialize(StreamBuffer *sb) const { sb->write_int32(size()); for (const auto &pair : *this) { pair.second.serialize(sb); } } -void HttpOutRequestMap::deserialize(StreamBuffer *sb) { +void HttpClientRequestMap::deserialize(StreamBuffer *sb) { int32_t count = sb->read_int32(); clear(); - HttpOutRequest req; + HttpClientRequest req; for (int i = 0; i < count; i++) { req.deserialize(sb); (*this)[req.request_id()] = req; } } -HttpInResponse::HttpInResponse() { +HttpClientResponse::HttpClientResponse() { + request_id_ = 0; status_code_ = 0; response_length_ = 0; mime_type_ = ""; content_length_ = -1; } -eng::string HttpInResponse::DebugString() const { +eng::string HttpClientResponse::DebugString() const { eng::ostringstream oss; - oss << "HttpInResponse:" << std::endl; + oss << "HttpClientResponse:" << std::endl; oss << " status_code: " << status_code_ << std::endl; oss << " error: " << error_ << std::endl; oss << " content_length: " << content_length_ << std::endl; @@ -565,7 +566,7 @@ eng::string HttpInResponse::DebugString() const { return oss.str(); } -void HttpInResponse::fail(int code, string_view message) { +void HttpClientResponse::fail(int code, string_view message) { status_code_ = code; error_ = message; mime_type_ = ""; @@ -573,7 +574,7 @@ void HttpInResponse::fail(int code, string_view message) { content_ = ""; } -void HttpInResponse::incomplete(bool closed) { +void HttpClientResponse::incomplete(bool closed) { if (closed) { fail(500, "internal server error: response truncated"); } else { @@ -581,11 +582,11 @@ void HttpInResponse::incomplete(bool closed) { } } -void HttpInResponse::parse_content_encoding(string_view value) { +void HttpClientResponse::parse_content_encoding(string_view value) { content_encoding_ = util::ascii_tolower(value); } -void HttpInResponse::parse_content_length(string_view value) { +void HttpClientResponse::parse_content_length(string_view value) { int64_t code = sv::to_int64(value); if ((code < 0) || (code > INT_MAX)) { fail(500, util::ss("internal server error: unparseable content-length: ", value)); @@ -593,7 +594,7 @@ void HttpInResponse::parse_content_length(string_view value) { content_length_ = code; } -void HttpInResponse::parse_content_type(string_view value) { +void HttpClientResponse::parse_content_type(string_view value) { eng::string ctype = util::ascii_tolower(value); string_view ctview(ctype); mime_type_ = sv::trim(sv::read_to_sep(ctview, ';')); @@ -613,15 +614,15 @@ void HttpInResponse::parse_content_type(string_view value) { } } -void HttpInResponse::parse_location(string_view value) { +void HttpClientResponse::parse_location(string_view value) { location_ = url_decode(value); } -void HttpInResponse::parse_transfer_encoding(string_view value) { +void HttpClientResponse::parse_transfer_encoding(string_view value) { transfer_encoding_ = util::ascii_tolower(value); } -void HttpInResponse::parse_header(string_view header, string_view value) { +void HttpClientResponse::parse_header(string_view header, string_view value) { if (header == "content-encoding") { parse_content_encoding(value); } else if (header == "content-length") { @@ -637,7 +638,7 @@ void HttpInResponse::parse_header(string_view header, string_view value) { } } -bool HttpInResponse::parse_content_basic(std::string_view &view, bool closed) { +bool HttpClientResponse::parse_content_basic(std::string_view &view, bool closed) { if (content_length_ >= 0) { if (content_length_ > MAX_CONTENT_LENGTH) { fail(413, util::ss("payload too large: luprex limit=", MAX_CONTENT_LENGTH)); @@ -662,7 +663,7 @@ bool HttpInResponse::parse_content_basic(std::string_view &view, bool closed) { return true; } -bool HttpInResponse::parse_content_chunked(std::string_view &view, bool closed) { +bool HttpClientResponse::parse_content_chunked(std::string_view &view, bool closed) { int64_t total_size = 0; std::vector chunks; while (true) { @@ -711,7 +712,7 @@ bool HttpInResponse::parse_content_chunked(std::string_view &view, bool closed) return true; } -void HttpInResponse::parse(const StreamBuffer *sb, bool closed) { +void HttpClientResponse::parse(const StreamBuffer *sb, bool closed) { // We're not going to modify the StreamBuffer at all. // Instead, we work entirely on a view. string_view view = sb->view(); @@ -724,19 +725,26 @@ void HttpInResponse::parse(const StreamBuffer *sb, bool closed) { } // Parse the status line. + string_view protoversion = sv::read_to_space(status); + if (!sv::has_prefix(protoversion, "HTTP/")) { + fail(500, util::ss("internal server error: status line appears corrupt")); + return; + } string_view scode = sv::read_to_space(status); int64_t code = sv::to_int64(scode, 0); if ((code < 100) || (code > 599)) { fail(500, util::ss("internal server error: invalid response code: ", scode)); + return; } status_code_ = code; // Responses outside the range 200-299 are errors, // and therefore must store an error message. if ((code < 200) || (code > 299)) { - error_ = status; - if (error_.empty()) { - fail(code, util::ss("error code ", code)); + if (status.empty()) { + error_ = util::ss("error code ", code); + } else { + error_ = status; } } @@ -829,7 +837,7 @@ void HttpInResponse::parse(const StreamBuffer *sb, bool closed) { } } -void HttpInResponse::store(LuaStack &LS0, LuaSlot tab) const { +void HttpClientResponse::store(LuaStack &LS0, LuaSlot tab) const { LuaStack LS(LS0.state()); LS.newtable(tab); @@ -860,8 +868,8 @@ void HttpInResponse::store(LuaStack &LS0, LuaSlot tab) const { } } -void HttpInResponse::store_fail(LuaStack &LS, LuaSlot tab, int status_code, std::string_view error) { - HttpInResponse response; +void HttpClientResponse::store_fail(LuaStack &LS, LuaSlot tab, int status_code, std::string_view error) { + HttpClientResponse response; response.fail(status_code, error); response.store(LS, tab); } @@ -912,7 +920,7 @@ LuaDefine(http_request, "request", LuaArg tab; LuaRet str; LuaStack LS(L, tab, str); - HttpOutRequest req; + HttpClientRequest req; req.set_config(LS, tab); req.set_defaults(); eng::string error = req.check(); @@ -969,7 +977,7 @@ LuaDefine(http_response, "response", LuaArg text; LuaRet tab; LuaStack LS(L, text, tab); - HttpInResponse resp; + HttpClientResponse resp; StreamBuffer sb; sb.write_bytes(LS.ckstring(text)); resp.parse(&sb, true); diff --git a/luprex/core/cpp/http.hpp b/luprex/core/cpp/http.hpp index c315cf49..bbf86404 100644 --- a/luprex/core/cpp/http.hpp +++ b/luprex/core/cpp/http.hpp @@ -19,10 +19,11 @@ #include "wrap-map.hpp" #include "luastack.hpp" #include "streambuffer.hpp" +#include "drivenengine.hpp" using UrlParameters = eng::map; -class HttpOutRequest : public eng::nevernew { +class HttpClientRequest : public eng::nevernew { private: // Request IDs. int64_t request_id_; @@ -59,14 +60,10 @@ private: public: // Construct an empty HTTP request. // All of the fields have empty values. - HttpOutRequest(); + HttpClientRequest(); - // Get the request IDs. - int64_t request_id() const { return request_id_; } - int64_t place_id() const { return place_id_; } - int64_t thread_id() const { return thread_id_; } - // Get request-related fields. + // const eng::string &error() const { return error_; } bool verify_certificate() const { return verify_certificate_; } const eng::string &method() const { return method_; } @@ -74,20 +71,13 @@ public: int port() const { return port_; } const eng::string &path() const { return path_; } - // Get the network target, eg, "cert:host:port" - eng::string target() const; - - // Set the request IDs. - void set_request_id(int64_t request_id) { request_id_ = request_id; } - void set_place_id(int64_t place_id) { place_id_ = place_id; } - void set_thread_id(int64_t thread_id) { thread_id_ = thread_id; } - - // Populate an HTTP request a piece at a time. + // Populate an request-related fields one piece at a time. // If you pass an invalid value, or if the field is // already set, the routine will generate an error message // and store it in the error field. In that case, the set // will not happen. If there's already an error in the error // field, it will not be overwritten. + // void set_verify_certificate(bool flag); void set_method(const eng::string &method); void set_host(const eng::string &host); @@ -96,7 +86,6 @@ public: void set_param(const eng::string &key, const eng::string &value); void set_url(std::string_view url); - // Same as above, but using Lua values. void set_verify_certificate(LuaStack &LS, LuaSlot val); void set_method(LuaStack &LS, LuaSlot val); void set_host(LuaStack &LS, LuaSlot val); @@ -106,18 +95,29 @@ public: void set_params(LuaStack &LS, LuaSlot tab); void set_url(LuaStack &LS, LuaSlot val); - // Set default values for any fields that should have - // defaults. This must be done after setting regular - // values. + // Set default values for method and port. + // This must be done after setting regular values. void set_defaults(); + // Populate request-related fields from a Lua table. + void set_config(LuaStack &LS0, LuaSlot tab); + + // Get or Set the request IDs. + // This class does just stores these. + int64_t request_id() const { return request_id_; } + int64_t place_id() const { return place_id_; } + int64_t thread_id() const { return thread_id_; } + void set_request_id(int64_t request_id) { request_id_ = request_id; } + void set_place_id(int64_t place_id) { place_id_ = place_id; } + void set_thread_id(int64_t thread_id) { thread_id_ = thread_id; } + + // Get the network target, eg, "cert:host:port" + eng::string target() const; + // Verify that the request is error free and that // defaults have been set. eng::string check() const; - // Populate an HTTP request from a Lua table. - void set_config(LuaStack &LS0, LuaSlot tab); - // Put the request into the stream, assuming HTTP/1.1 void send(StreamBuffer *target) const { send_internal(target, false); } @@ -129,14 +129,11 @@ public: eng::string DebugString(); }; -class HttpOutRequestMap : public eng::map { -public: - void serialize(StreamBuffer *sb) const; - void deserialize(StreamBuffer *sb); -}; - -class HttpInResponse { +class HttpClientResponse { private: + // The request ID. + int64_t request_id_; + // The HTTP response status code. int status_code_; @@ -198,7 +195,7 @@ public: const int64_t MAX_CONTENT_LENGTH = 1000000; // Construct a blank response. - HttpInResponse(); + HttpClientResponse(); // Store a result code and an error message, and clear the content. // This is generally used when the client detects an error, @@ -209,7 +206,7 @@ public: // Parse the HTTP response. The closed flag is to be set to true if the // remote has closed the connection. // - // If the request is incomplete, generates a 600 incomplete error. In that + // If the request is incomplete, generates a status code of zero. In that // case, loading more data from the server might improve the situation. // // Note that the response is not ever removed from the StreamBuffer, which @@ -218,6 +215,14 @@ public: // void parse(const StreamBuffer *sb, bool closed); + // Return true if the response is complete. + bool complete() const { return status_code_ != 0; } + + // Get or Set the request ID. + // This class does nothing with the request ID, it just stores it. + int64_t request_id() const { return request_id_; } + void set_request_id(int64_t v) { request_id_ = v; } + // Convert the HTTP response to a lua table. void store(LuaStack &LS, LuaSlot tab) const; @@ -228,4 +233,25 @@ public: static void store_fail(LuaStack &LS, LuaSlot tab, int status_code, std::string_view error); }; +class HttpClientRequestMap : public eng::map { +public: + void serialize(StreamBuffer *sb) const; + void deserialize(StreamBuffer *sb); +}; + +using HttpClientResponseVec = eng::vector; + +// This class associates an HTTP request to an actual communication +// channel that is executing that request. + +class HttpClientChannel { +public: + SharedChannel channel_; + int64_t parsed_bytes_; + + HttpClientChannel() : parsed_bytes_(0) {} +}; + +using HttpClientChannelMap = eng::map; + #endif // HTTP_HPP diff --git a/luprex/core/cpp/lpxserver.cpp b/luprex/core/cpp/lpxserver.cpp index 6d5ae362..00971446 100644 --- a/luprex/core/cpp/lpxserver.cpp +++ b/luprex/core/cpp/lpxserver.cpp @@ -25,6 +25,7 @@ public: LuaConsole console_; ClientVector clients_; PrintChanneler print_channeler_; + HttpClientChannelMap http_client_channels_; int64_t admin_id_; Gui gui_; @@ -201,6 +202,41 @@ public: while (handle_invocation(client)); } util::remove_nullptrs(clients_); + + // Look for new outgoing HTTP client requests. + for (const auto &pair : master_->http_requests()) { + const HttpClientRequest &request = pair.second; + HttpClientChannel &channel = http_client_channels_[request.request_id()]; + if (channel.channel_ == nullptr) { + channel.channel_ = new_outgoing_channel(request.target()); + channel.parsed_bytes_ = 0; + request.send(channel.channel_->out()); + } + } + + // Maintain existing outgoing HTTP client requests. + HttpClientResponseVec http_responses; + for (auto &pair : http_client_channels_) { + HttpClientChannel &htchan = pair.second; + Channel &channel = *htchan.channel_; + if (channel.closed() || (channel.in()->fill() > htchan.parsed_bytes_)) { + HttpClientResponse response; + if (!channel.error().empty()) { + response.fail(503, util::ss("Service Unavailable: ", channel.error())); + } else { + htchan.parsed_bytes_ = channel.in()->fill(); + response.parse(channel.in(), channel.closed()); + } + if (response.complete()) { + response.set_request_id(pair.first); + http_responses.push_back(response); + } + } + } + for (const HttpClientResponse &response : http_responses) { + http_client_channels_.erase(response.request_id()); + } + master_->http_responses(http_responses); } }; diff --git a/luprex/core/cpp/world-accessor.cpp b/luprex/core/cpp/world-accessor.cpp index 769fbeda..71adc8d1 100644 --- a/luprex/core/cpp/world-accessor.cpp +++ b/luprex/core/cpp/world-accessor.cpp @@ -532,14 +532,14 @@ LuaDefine(http_get, "request", LuaArg request; LuaRet response; LuaStack LS(L, request, response); - HttpOutRequest req; + HttpClientRequest req; // Parse the request and make sure it's valid. req.set_config(LS, request); req.set_defaults(); eng::string error = req.check(); if (!error.empty()) { - HttpInResponse::store_fail(LS, response, 400, util::ss("bad request: ", error)); + HttpClientResponse::store_fail(LS, response, 400, util::ss("bad request: ", error)); return LS.result(); } diff --git a/luprex/core/cpp/world-core.cpp b/luprex/core/cpp/world-core.cpp index ee03bb03..7197a1b9 100644 --- a/luprex/core/cpp/world-core.cpp +++ b/luprex/core/cpp/world-core.cpp @@ -393,13 +393,13 @@ void World::update_source(const util::LuaSourceVec &source) { assert(stack_is_clear()); } -void World::http_response(int64_t request_id, const HttpInResponse &response) { +void World::http_response(const HttpClientResponse &response) { // Find the request. - auto iter = http_requests_.find(request_id); + auto iter = http_requests_.find(response.request_id()); if (iter == http_requests_.end()) { return; } - HttpOutRequest request = iter->second; + HttpClientRequest request = iter->second; http_requests_.erase(iter); // Get the place and thread as lua objects. @@ -443,13 +443,18 @@ void World::http_response(int64_t request_id, const HttpInResponse &response) { run_scheduled_threads(); } +void World::http_responses(const HttpClientResponseVec &responses) { + for (const HttpClientResponse &response : responses) { + http_response(response); + } +} + void World::abort_all_http_requests(int status_code, std::string_view error) { - HttpInResponse abortresponse; + HttpClientResponse abortresponse; abortresponse.fail(status_code, error); - while (true) { - auto iter = http_requests_.begin(); - if (iter == http_requests_.end()) break; - http_response(iter->second.request_id(), abortresponse); + while (!http_requests_.empty()) { + abortresponse.set_request_id(http_requests_.begin()->first); + http_response(abortresponse); } } diff --git a/luprex/core/cpp/world.hpp b/luprex/core/cpp/world.hpp index 66ef47a1..fd6260b4 100644 --- a/luprex/core/cpp/world.hpp +++ b/luprex/core/cpp/world.hpp @@ -206,8 +206,9 @@ public: void update_source(const util::LuaSourceVec &source); // Supply an HTTP response to an outstanding HTTP request. - void http_response(int64_t request_id, const HttpInResponse &response); - + void http_response(const HttpClientResponse &response); + void http_responses(const HttpClientResponseVec &responses); + // Abort all HTTP requests. This is typically used after // reloading a world from a save-game. The http requests that // were in progress are long-since dead. @@ -230,7 +231,7 @@ public: // Get a table showing all outstanding HTTP requests. // - const HttpOutRequestMap &http_requests() const { return http_requests_; } + const HttpClientRequestMap &http_requests() const { return http_requests_; } // Serialize and deserialize. // @@ -515,7 +516,7 @@ private: // Outstanding HTTP requests, indexed by request ID. // Authoritative models only. // - HttpOutRequestMap http_requests_; + HttpClientRequestMap http_requests_; // Serialized snapshot of world model. //