1
0
Fork 0
mirror of https://github.com/ton-blockchain/ton synced 2025-02-12 11:12:16 +00:00

Correctly return errors from proxy

This commit is contained in:
SpyCheese 2022-06-29 15:53:48 +03:00
parent c55b6f84a5
commit 9107bcaf24
6 changed files with 75 additions and 36 deletions

View file

@ -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));

View file

@ -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;

View file

@ -864,7 +864,7 @@ tl_object_ptr<ton_api::http_response> HttpResponse::store_tl() {
} else {
headers.push_back(HttpHeader{"Connection", "Close"}.store_tl());
}
return create_tl_object<ton_api::http_response>(proto_version_, code_, reason_, std::move(headers));
return create_tl_object<ton_api::http_response>(proto_version_, code_, reason_, std::move(headers), false);
}
td::Status HttpHeader::basic_check() {

View file

@ -122,10 +122,15 @@ class HttpRemote : public td::actor::Actor {
private:
td::IPAddress addr_;
bool ready_ = false;
bool ready_ = true;
td::actor::ActorOwn<ton::http::HttpClient> client_;
};
td::BufferSlice create_error_response(const std::string& proto_version, int code, const std::string& reason) {
return ton::create_serialize_tl_object<ton::ton_api::http_response>(
proto_version, code, reason, std::vector<ton::tl_object_ptr<ton::ton_api::http_header>>(), true);
}
class HttpRldpPayloadReceiver : public td::actor::Actor {
public:
HttpRldpPayloadReceiver(std::shared_ptr<ton::http::HttpPayload> 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<HttpRldpPayloadReceiver>("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<HttpRldpPayloadReceiver>("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::unique_ptr<ton::http::HttpResponse>, std::shared_ptr<ton::http::HttpPayload>> R) {
td::actor::create_actor<HttpRldpPayloadSender>("HttpPayloadSender(R)", std::move(R.second), id_, local_id_, adnl_,
rldp_)
.release();
if (R.first->need_payload()) {
td::actor::create_actor<HttpRldpPayloadSender>("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<td::BufferSlice> promise) {
LOG(INFO) << "got HTTP request over rldp from " << src;
TRY_RESULT_PROMISE(promise, f, ton::fetch_tl_object<ton::ton_api::http_request>(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<ton::http::HttpRequest> 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<HttpRemote>("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<RldpToTcpRequestSender>("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<td::BufferSlice> promise) {
TRY_RESULT_PROMISE(promise, fd, td::SocketFd::open(ip));
std::string http_version, td::IPAddress ip, td::Promise<td::BufferSlice> 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<RldpTcpTunnel>(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<ton::ton_api::http_response>(
"HTTP/1.1", 200, "Connection Established", std::vector<ton::tl_object_ptr<ton::ton_api::http_header>>()));
http_version, 200, "Connection Established", std::vector<ton::tl_object_ptr<ton::ton_api::http_header>>(),
false));
}
void add_adnl_addr(ton::adnl::AdnlNodeIdShort id) {

View file

@ -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---

Binary file not shown.