diff --git a/http/http-inbound-connection.cpp b/http/http-inbound-connection.cpp index ef2f3a58..89c9c123 100644 --- a/http/http-inbound-connection.cpp +++ b/http/http-inbound-connection.cpp @@ -44,13 +44,22 @@ void HttpInboundConnection::send_server_error() { loop(); } -void HttpInboundConnection::send_proxy_error() { - static const auto s = - "HTTP/1.1 502 Bad Gateway\r\n" - "Connection: keep-alive\r\n" - "Content-length: 0\r\n" - "\r\n"; - buffered_fd_.output_buffer().append(td::Slice(s, strlen(s))); +void HttpInboundConnection::send_proxy_error(td::Status error) { + if (error.code() == ErrorCode::timeout) { + static const auto s = + "HTTP/1.1 504 Gateway Timeout\r\n" + "Connection: keep-alive\r\n" + "Content-length: 0\r\n" + "\r\n"; + buffered_fd_.output_buffer().append(td::Slice(s, strlen(s))); + } else { + static const auto s = + "HTTP/1.1 502 Bad Gateway\r\n" + "Connection: keep-alive\r\n" + "Content-length: 0\r\n" + "\r\n"; + buffered_fd_.output_buffer().append(td::Slice(s, strlen(s))); + } loop(); } @@ -83,7 +92,7 @@ td::Status HttpInboundConnection::receive(td::ChainBufferReader &input) { auto a = R.move_as_ok(); td::actor::send_closure(SelfId, &HttpInboundConnection::send_answer, std::move(a.first), std::move(a.second)); } else { - td::actor::send_closure(SelfId, &HttpInboundConnection::send_proxy_error); + td::actor::send_closure(SelfId, &HttpInboundConnection::send_proxy_error, R.move_as_error()); } }); http_callback_->receive_request(std::move(cur_request_), payload, std::move(P)); diff --git a/http/http-inbound-connection.h b/http/http-inbound-connection.h index c63e0a30..e3602267 100644 --- a/http/http-inbound-connection.h +++ b/http/http-inbound-connection.h @@ -54,7 +54,7 @@ class HttpInboundConnection : public HttpConnection { void send_client_error(); void send_server_error(); - void send_proxy_error(); + void send_proxy_error(td::Status error); void payload_written() override { writing_payload_ = nullptr; diff --git a/http/http.cpp b/http/http.cpp index 427032f4..c99a5ec4 100644 --- a/http/http.cpp +++ b/http/http.cpp @@ -864,7 +864,7 @@ tl_object_ptr HttpResponse::store_tl() { } else { headers.push_back(HttpHeader{"Connection", "Close"}.store_tl()); } - return create_tl_object(proto_version_, code_, reason_, std::move(headers)); + return create_tl_object(proto_version_, code_, reason_, std::move(headers), false); } td::Status HttpHeader::basic_check() { diff --git a/rldp-http-proxy/rldp-http-proxy.cpp b/rldp-http-proxy/rldp-http-proxy.cpp index 6ecb8e3a..98088713 100644 --- a/rldp-http-proxy/rldp-http-proxy.cpp +++ b/rldp-http-proxy/rldp-http-proxy.cpp @@ -122,10 +122,15 @@ class HttpRemote : public td::actor::Actor { private: td::IPAddress addr_; - bool ready_ = false; + bool ready_ = true; td::actor::ActorOwn client_; }; +td::BufferSlice create_error_response(const std::string& proto_version, int code, const std::string& reason) { + return ton::create_serialize_tl_object( + proto_version, code, reason, std::vector>(), true); +} + class HttpRldpPayloadReceiver : public td::actor::Actor { public: HttpRldpPayloadReceiver(std::shared_ptr payload, td::Bits256 transfer_id, @@ -499,7 +504,7 @@ class TcpToRldpRequestSender : public td::actor::Actor { } auto f = F.move_as_ok(); auto R = ton::http::HttpResponse::create( - f->http_version_, f->status_code_, f->reason_, false, true, is_tunnel() && f->status_code_ == 200); + f->http_version_, f->status_code_, f->reason_, f->no_payload_, true, is_tunnel() && f->status_code_ == 200); if (R.is_error()) { abort_query(R.move_as_error()); return; @@ -529,9 +534,13 @@ class TcpToRldpRequestSender : public td::actor::Actor { td::actor::send_closure(SelfId, &TcpToRldpRequestSender::finished_payload_transfer); } }); - td::actor::create_actor("HttpPayloadReceiver", response_payload_, id_, dst_, local_id_, - adnl_, rldp_, is_tunnel()) - .release(); + if (f->no_payload_) { + response_payload_->complete_parse(); + } else { + td::actor::create_actor("HttpPayloadReceiver", response_payload_, id_, dst_, local_id_, + adnl_, rldp_, is_tunnel()) + .release(); + } promise_.set_value(std::make_pair(std::move(response_), std::move(response_payload_))); stop(); @@ -543,6 +552,7 @@ class TcpToRldpRequestSender : public td::actor::Actor { void abort_query(td::Status error) { LOG(INFO) << "aborting http over rldp query: " << error; + promise_.set_error(std::move(error)); stop(); } @@ -808,9 +818,11 @@ class RldpToTcpRequestSender : public td::actor::Actor { } void got_result(std::pair, std::shared_ptr> R) { - td::actor::create_actor("HttpPayloadSender(R)", std::move(R.second), id_, local_id_, adnl_, - rldp_) - .release(); + if (R.first->need_payload()) { + td::actor::create_actor("HttpPayloadSender(R)", std::move(R.second), id_, local_id_, adnl_, + rldp_) + .release(); + } auto f = ton::serialize_tl_object(R.first->store_tl(), true); promise_.set_value(std::move(f)); stop(); @@ -818,7 +830,7 @@ class RldpToTcpRequestSender : public td::actor::Actor { void abort_query(td::Status error) { LOG(INFO) << "aborting http over rldp query: " << error; - promise_.set_error(std::move(error)); + promise_.set_result(create_error_response(request_->proto_version(), 502, "Bad Gateway")); stop(); } @@ -1174,13 +1186,22 @@ class RldpHttpProxy : public td::actor::Actor { td::Promise promise) { LOG(INFO) << "got HTTP request over rldp from " << src; TRY_RESULT_PROMISE(promise, f, ton::fetch_tl_object(data, true)); - TRY_RESULT_PROMISE(promise, request, ton::http::HttpRequest::create(f->method_, f->url_, f->http_version_)); - for (auto &x : f->headers_) { - ton::http::HttpHeader h{x->name_, x->value_}; - TRY_STATUS_PROMISE(promise, h.basic_check()); - request->add_header(std::move(h)); + std::unique_ptr request; + auto S = [&]() { + TRY_RESULT_ASSIGN(request, ton::http::HttpRequest::create(f->method_, f->url_, f->http_version_)); + for (auto &x : f->headers_) { + ton::http::HttpHeader h{x->name_, x->value_}; + TRY_STATUS(h.basic_check()); + request->add_header(std::move(h)); + } + TRY_STATUS(request->complete_parse_header()); + return td::Status::OK(); + }(); + if (S.is_error()) { + LOG(INFO) << "Failed to parse http request: " << S; + promise.set_result(create_error_response(f->http_version_, 400, "Bad Request")); + return; } - TRY_STATUS_PROMISE(promise, request->complete_parse_header()); auto host = request->host(); td::uint16 port = 80; if (host.empty()) { @@ -1212,7 +1233,7 @@ class RldpHttpProxy : public td::actor::Actor { port = (td::uint16)std::stoul(host.substr(p + 1)); } catch (const std::logic_error &) { port = 80; - promise.set_error(td::Status::Error(PSLICE() << "Invalid port '" << host.substr(p + 1) << "'")); + promise.set_result(create_error_response(f->http_version_, 400, "Bad Request")); return; } host = host.substr(0, p); @@ -1224,19 +1245,19 @@ class RldpHttpProxy : public td::actor::Actor { if (it == hosts_.end()) { it = hosts_.find("*"); if (it == hosts_.end()) { - promise.set_error(td::Status::Error(ton::ErrorCode::error, "unknown server name")); + promise.set_result(create_error_response(f->http_version_, 502, "Bad Gateway")); return; } } auto it2 = it->second.ports_.find(port); if (it2 == it->second.ports_.end()) { - promise.set_error(td::Status::Error(ton::ErrorCode::error, "unknown host:port")); + promise.set_result(create_error_response(f->http_version_, 502, "Bad Gateway")); return; } auto &server = it2->second; if (request->method() == "CONNECT") { LOG(INFO) << "starting HTTP tunnel over RLDP to " << server.remote_addr_; - start_tcp_tunnel(f->id_, src, dst, server.remote_addr_, std::move(promise)); + start_tcp_tunnel(f->id_, src, dst, f->http_version_, server.remote_addr_, std::move(promise)); return; } @@ -1244,22 +1265,31 @@ class RldpHttpProxy : public td::actor::Actor { server.http_remote_ = td::actor::create_actor("remote", server.remote_addr_); } - TRY_RESULT_PROMISE(promise, payload, request->create_empty_payload()); + auto payload = request->create_empty_payload(); + if (payload.is_error()) { + promise.set_result(create_error_response(f->http_version_, 502, "Bad Gateway")); + return; + } LOG(INFO) << "starting HTTP over RLDP request"; td::actor::create_actor("inboundreq", f->id_, dst, src, std::move(request), - std::move(payload), std::move(promise), adnl_.get(), rldp_.get(), + payload.move_as_ok(), std::move(promise), adnl_.get(), rldp_.get(), server.http_remote_.get()) .release(); } void start_tcp_tunnel(td::Bits256 id, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort local_id, - td::IPAddress ip, td::Promise promise) { - TRY_RESULT_PROMISE(promise, fd, td::SocketFd::open(ip)); + std::string http_version, td::IPAddress ip, td::Promise promise) { + auto fd = td::SocketFd::open(ip); + if (fd.is_error()) { + promise.set_result(create_error_response(http_version, 502, "Bad Gateway")); + return; + } td::actor::create_actor(td::actor::ActorOptions().with_name("tunnel").with_poll(), id, src, local_id, - adnl_.get(), rldp_.get(), std::move(fd)).release(); + adnl_.get(), rldp_.get(), fd.move_as_ok()).release(); promise.set_result(ton::create_serialize_tl_object( - "HTTP/1.1", 200, "Connection Established", std::vector>())); + http_version, 200, "Connection Established", std::vector>(), + false)); } void add_adnl_addr(ton::adnl::AdnlNodeIdShort id) { diff --git a/tl/generate/scheme/ton_api.tl b/tl/generate/scheme/ton_api.tl index 87dadd8a..bed1fc10 100644 --- a/tl/generate/scheme/ton_api.tl +++ b/tl/generate/scheme/ton_api.tl @@ -705,7 +705,7 @@ storage.queryPrefix id:int256 = Object; http.header name:string value:string = http.Header; http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart; -http.response http_version:string status_code:int reason:string headers:(vector http.header) = http.Response; +http.response http_version:string status_code:int reason:string headers:(vector http.header) no_payload:Bool = http.Response; ---functions--- diff --git a/tl/generate/scheme/ton_api.tlo b/tl/generate/scheme/ton_api.tlo index 9fb0cc43..f7279060 100644 Binary files a/tl/generate/scheme/ton_api.tlo and b/tl/generate/scheme/ton_api.tlo differ