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:
parent
c55b6f84a5
commit
9107bcaf24
6 changed files with 75 additions and 36 deletions
|
@ -44,13 +44,22 @@ void HttpInboundConnection::send_server_error() {
|
||||||
loop();
|
loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpInboundConnection::send_proxy_error() {
|
void HttpInboundConnection::send_proxy_error(td::Status error) {
|
||||||
static const auto s =
|
if (error.code() == ErrorCode::timeout) {
|
||||||
"HTTP/1.1 502 Bad Gateway\r\n"
|
static const auto s =
|
||||||
"Connection: keep-alive\r\n"
|
"HTTP/1.1 504 Gateway Timeout\r\n"
|
||||||
"Content-length: 0\r\n"
|
"Connection: keep-alive\r\n"
|
||||||
"\r\n";
|
"Content-length: 0\r\n"
|
||||||
buffered_fd_.output_buffer().append(td::Slice(s, strlen(s)));
|
"\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();
|
loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +92,7 @@ td::Status HttpInboundConnection::receive(td::ChainBufferReader &input) {
|
||||||
auto a = R.move_as_ok();
|
auto a = R.move_as_ok();
|
||||||
td::actor::send_closure(SelfId, &HttpInboundConnection::send_answer, std::move(a.first), std::move(a.second));
|
td::actor::send_closure(SelfId, &HttpInboundConnection::send_answer, std::move(a.first), std::move(a.second));
|
||||||
} else {
|
} 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));
|
http_callback_->receive_request(std::move(cur_request_), payload, std::move(P));
|
||||||
|
|
|
@ -54,7 +54,7 @@ class HttpInboundConnection : public HttpConnection {
|
||||||
|
|
||||||
void send_client_error();
|
void send_client_error();
|
||||||
void send_server_error();
|
void send_server_error();
|
||||||
void send_proxy_error();
|
void send_proxy_error(td::Status error);
|
||||||
|
|
||||||
void payload_written() override {
|
void payload_written() override {
|
||||||
writing_payload_ = nullptr;
|
writing_payload_ = nullptr;
|
||||||
|
|
|
@ -864,7 +864,7 @@ tl_object_ptr<ton_api::http_response> HttpResponse::store_tl() {
|
||||||
} else {
|
} else {
|
||||||
headers.push_back(HttpHeader{"Connection", "Close"}.store_tl());
|
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() {
|
td::Status HttpHeader::basic_check() {
|
||||||
|
|
|
@ -122,10 +122,15 @@ class HttpRemote : public td::actor::Actor {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
td::IPAddress addr_;
|
td::IPAddress addr_;
|
||||||
bool ready_ = false;
|
bool ready_ = true;
|
||||||
td::actor::ActorOwn<ton::http::HttpClient> client_;
|
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 {
|
class HttpRldpPayloadReceiver : public td::actor::Actor {
|
||||||
public:
|
public:
|
||||||
HttpRldpPayloadReceiver(std::shared_ptr<ton::http::HttpPayload> payload, td::Bits256 transfer_id,
|
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 f = F.move_as_ok();
|
||||||
auto R = ton::http::HttpResponse::create(
|
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()) {
|
if (R.is_error()) {
|
||||||
abort_query(R.move_as_error());
|
abort_query(R.move_as_error());
|
||||||
return;
|
return;
|
||||||
|
@ -529,9 +534,13 @@ class TcpToRldpRequestSender : public td::actor::Actor {
|
||||||
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::finished_payload_transfer);
|
td::actor::send_closure(SelfId, &TcpToRldpRequestSender::finished_payload_transfer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
td::actor::create_actor<HttpRldpPayloadReceiver>("HttpPayloadReceiver", response_payload_, id_, dst_, local_id_,
|
if (f->no_payload_) {
|
||||||
adnl_, rldp_, is_tunnel())
|
response_payload_->complete_parse();
|
||||||
.release();
|
} 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_)));
|
promise_.set_value(std::make_pair(std::move(response_), std::move(response_payload_)));
|
||||||
stop();
|
stop();
|
||||||
|
@ -543,6 +552,7 @@ class TcpToRldpRequestSender : public td::actor::Actor {
|
||||||
|
|
||||||
void abort_query(td::Status error) {
|
void abort_query(td::Status error) {
|
||||||
LOG(INFO) << "aborting http over rldp query: " << error;
|
LOG(INFO) << "aborting http over rldp query: " << error;
|
||||||
|
promise_.set_error(std::move(error));
|
||||||
stop();
|
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) {
|
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_,
|
if (R.first->need_payload()) {
|
||||||
rldp_)
|
td::actor::create_actor<HttpRldpPayloadSender>("HttpPayloadSender(R)", std::move(R.second), id_, local_id_, adnl_,
|
||||||
.release();
|
rldp_)
|
||||||
|
.release();
|
||||||
|
}
|
||||||
auto f = ton::serialize_tl_object(R.first->store_tl(), true);
|
auto f = ton::serialize_tl_object(R.first->store_tl(), true);
|
||||||
promise_.set_value(std::move(f));
|
promise_.set_value(std::move(f));
|
||||||
stop();
|
stop();
|
||||||
|
@ -818,7 +830,7 @@ class RldpToTcpRequestSender : public td::actor::Actor {
|
||||||
|
|
||||||
void abort_query(td::Status error) {
|
void abort_query(td::Status error) {
|
||||||
LOG(INFO) << "aborting http over rldp query: " << 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();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1174,13 +1186,22 @@ class RldpHttpProxy : public td::actor::Actor {
|
||||||
td::Promise<td::BufferSlice> promise) {
|
td::Promise<td::BufferSlice> promise) {
|
||||||
LOG(INFO) << "got HTTP request over rldp from " << src;
|
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, 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_));
|
std::unique_ptr<ton::http::HttpRequest> request;
|
||||||
for (auto &x : f->headers_) {
|
auto S = [&]() {
|
||||||
ton::http::HttpHeader h{x->name_, x->value_};
|
TRY_RESULT_ASSIGN(request, ton::http::HttpRequest::create(f->method_, f->url_, f->http_version_));
|
||||||
TRY_STATUS_PROMISE(promise, h.basic_check());
|
for (auto &x : f->headers_) {
|
||||||
request->add_header(std::move(h));
|
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();
|
auto host = request->host();
|
||||||
td::uint16 port = 80;
|
td::uint16 port = 80;
|
||||||
if (host.empty()) {
|
if (host.empty()) {
|
||||||
|
@ -1212,7 +1233,7 @@ class RldpHttpProxy : public td::actor::Actor {
|
||||||
port = (td::uint16)std::stoul(host.substr(p + 1));
|
port = (td::uint16)std::stoul(host.substr(p + 1));
|
||||||
} catch (const std::logic_error &) {
|
} catch (const std::logic_error &) {
|
||||||
port = 80;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
host = host.substr(0, p);
|
host = host.substr(0, p);
|
||||||
|
@ -1224,19 +1245,19 @@ class RldpHttpProxy : public td::actor::Actor {
|
||||||
if (it == hosts_.end()) {
|
if (it == hosts_.end()) {
|
||||||
it = hosts_.find("*");
|
it = hosts_.find("*");
|
||||||
if (it == hosts_.end()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto it2 = it->second.ports_.find(port);
|
auto it2 = it->second.ports_.find(port);
|
||||||
if (it2 == it->second.ports_.end()) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
auto &server = it2->second;
|
auto &server = it2->second;
|
||||||
if (request->method() == "CONNECT") {
|
if (request->method() == "CONNECT") {
|
||||||
LOG(INFO) << "starting HTTP tunnel over RLDP to " << server.remote_addr_;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1244,22 +1265,31 @@ class RldpHttpProxy : public td::actor::Actor {
|
||||||
server.http_remote_ = td::actor::create_actor<HttpRemote>("remote", server.remote_addr_);
|
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";
|
LOG(INFO) << "starting HTTP over RLDP request";
|
||||||
td::actor::create_actor<RldpToTcpRequestSender>("inboundreq", f->id_, dst, src, std::move(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())
|
server.http_remote_.get())
|
||||||
.release();
|
.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start_tcp_tunnel(td::Bits256 id, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort local_id,
|
void start_tcp_tunnel(td::Bits256 id, ton::adnl::AdnlNodeIdShort src, ton::adnl::AdnlNodeIdShort local_id,
|
||||||
td::IPAddress ip, td::Promise<td::BufferSlice> promise) {
|
std::string http_version, td::IPAddress ip, td::Promise<td::BufferSlice> promise) {
|
||||||
TRY_RESULT_PROMISE(promise, fd, td::SocketFd::open(ip));
|
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,
|
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>(
|
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) {
|
void add_adnl_addr(ton::adnl::AdnlNodeIdShort id) {
|
||||||
|
|
|
@ -705,7 +705,7 @@ storage.queryPrefix id:int256 = Object;
|
||||||
|
|
||||||
http.header name:string value:string = http.Header;
|
http.header name:string value:string = http.Header;
|
||||||
http.payloadPart data:bytes trailer:(vector http.header) last:Bool = http.PayloadPart;
|
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---
|
---functions---
|
||||||
|
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue