| 46 | } |
| 47 | |
| 48 | void ProxyRunningRequest::receive_answer_ex_impl(cocoon_api::proxy_queryAnswerEx &ans) { |
| 49 | if (sent_answer_) { |
| 50 | fail(td::Status::Error(ton::ErrorCode::protoviolation, "out of order answer parts")); |
| 51 | return; |
| 52 | } |
| 53 | |
| 54 | LOG(DEBUG) << "proxy request " << id_.to_hex() << ": received answer"; |
| 55 | |
| 56 | received_answer_time_unix_ = td::Clocks::system(); |
| 57 | |
| 58 | auto R = cocoon::fetch_tl_object<cocoon_api::http_response>(ans.answer_.as_slice(), true); |
| 59 | if (R.is_error()) { |
| 60 | fail(td::Status::Error(ton::ErrorCode::protoviolation, |
| 61 | PSTRING() << "received malformed answer from worker: " << R.move_as_error())); |
| 62 | return; |
| 63 | } |
| 64 | auto http_ans = R.move_as_ok(); |
| 65 | if (http_ans->payload_.size() > 0) { |
| 66 | stats()->answer_bytes_sent += (double)http_ans->payload_.size(); |
| 67 | payload_parts_++; |
| 68 | payload_bytes_ += http_ans->payload_.size(); |
| 69 | } |
| 70 | |
| 71 | bool is_completed = ans.flags_ & 1; |
| 72 | if (is_completed) { |
| 73 | CHECK(ans.final_info_); |
| 74 | tokens_used_ = std::move(ans.final_info_->tokens_used_); |
| 75 | worker_run_time_ = ans.final_info_->worker_end_time_ - ans.final_info_->worker_start_time_; |
| 76 | } |
| 77 | |
| 78 | // Add proxy timing headers to the existing HTTP response using Unix timestamps |
| 79 | http_ans->headers_.push_back(cocoon::cocoon_api::make_object<cocoon_api::http_header>( |
| 80 | "X-Cocoon-Proxy-Start", PSTRING() << td::StringBuilder::FixedDouble(start_time_unix_, 6))); |
| 81 | http_ans->headers_.push_back(cocoon::cocoon_api::make_object<cocoon_api::http_header>( |
| 82 | "X-Cocoon-Proxy-End", PSTRING() << td::StringBuilder::FixedDouble(td::Clocks::system(), 6))); |
| 83 | |
| 84 | // Re-serialize the modified HTTP response |
| 85 | auto modified_answer = cocoon::serialize_tl_object(http_ans, true); |
| 86 | |
| 87 | td::BufferSlice res; |
| 88 | if (client_proto_version_ == 0) { |
| 89 | res = cocoon::create_serialize_tl_object<cocoon_api::client_queryAnswer>(std::move(modified_answer), is_completed, |
| 90 | client_request_id_, tokens_used()); |
| 91 | } else { |
| 92 | ton::tl_object_ptr<cocoon_api::client_queryFinalInfo> final_info; |
| 93 | if (is_completed) { |
| 94 | final_info = create_final_info(ans.final_info_.get()); |
| 95 | } |
| 96 | res = cocoon::create_serialize_tl_object<cocoon_api::client_queryAnswerEx>( |
| 97 | client_request_id_, std::move(modified_answer), (is_completed ? 1 : 0), std::move(final_info)); |
| 98 | } |
| 99 | |
| 100 | td::actor::send_closure(runner_, &ProxyRunner::send_message_to_connection, client_connection_id_, std::move(res)); |
| 101 | |
| 102 | sent_answer_ = true; |
| 103 | |
| 104 | if (is_completed) { |
| 105 | finish(true); |
nothing calls this directly
no test coverage detected