]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/lib/cpp/src/thrift/async/TEvhttpClientChannel.cpp
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / lib / cpp / src / thrift / async / TEvhttpClientChannel.cpp
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20 #include <thrift/async/TEvhttpClientChannel.h>
21 #include <evhttp.h>
22 #include <event2/buffer.h>
23 #include <event2/buffer_compat.h>
24 #include <thrift/transport/TBufferTransports.h>
25 #include <thrift/protocol/TProtocolException.h>
26
27 #include <iostream>
28 #include <sstream>
29
30 using namespace apache::thrift::protocol;
31 using apache::thrift::transport::TTransportException;
32
33 namespace apache {
34 namespace thrift {
35 namespace async {
36
37 TEvhttpClientChannel::TEvhttpClientChannel(const std::string& host,
38 const std::string& path,
39 const char* address,
40 int port,
41 struct event_base* eb,
42 struct evdns_base* dnsbase)
43
44 : host_(host), path_(path), conn_(nullptr) {
45 conn_ = evhttp_connection_base_new(eb, dnsbase, address, port);
46 if (conn_ == nullptr) {
47 throw TException("evhttp_connection_new failed");
48 }
49 }
50
51 TEvhttpClientChannel::~TEvhttpClientChannel() {
52 if (conn_ != nullptr) {
53 evhttp_connection_free(conn_);
54 }
55 }
56
57 void TEvhttpClientChannel::sendAndRecvMessage(const VoidCallback& cob,
58 apache::thrift::transport::TMemoryBuffer* sendBuf,
59 apache::thrift::transport::TMemoryBuffer* recvBuf) {
60 struct evhttp_request* req = evhttp_request_new(response, this);
61 if (req == nullptr) {
62 throw TException("evhttp_request_new failed");
63 }
64
65 int rv;
66
67 rv = evhttp_add_header(req->output_headers, "Host", host_.c_str());
68 if (rv != 0) {
69 throw TException("evhttp_add_header failed");
70 }
71
72 rv = evhttp_add_header(req->output_headers, "Content-Type", "application/x-thrift");
73 if (rv != 0) {
74 throw TException("evhttp_add_header failed");
75 }
76
77 uint8_t* obuf;
78 uint32_t sz;
79 sendBuf->getBuffer(&obuf, &sz);
80 rv = evbuffer_add(req->output_buffer, obuf, sz);
81 if (rv != 0) {
82 throw TException("evbuffer_add failed");
83 }
84
85 rv = evhttp_make_request(conn_, req, EVHTTP_REQ_POST, path_.c_str());
86 if (rv != 0) {
87 throw TException("evhttp_make_request failed");
88 }
89
90 completionQueue_.push(Completion(cob, recvBuf));
91 }
92
93 void TEvhttpClientChannel::sendMessage(const VoidCallback& cob,
94 apache::thrift::transport::TMemoryBuffer* message) {
95 (void)cob;
96 (void)message;
97 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
98 "Unexpected call to TEvhttpClientChannel::sendMessage");
99 }
100
101 void TEvhttpClientChannel::recvMessage(const VoidCallback& cob,
102 apache::thrift::transport::TMemoryBuffer* message) {
103 (void)cob;
104 (void)message;
105 throw TProtocolException(TProtocolException::NOT_IMPLEMENTED,
106 "Unexpected call to TEvhttpClientChannel::recvMessage");
107 }
108
109 void TEvhttpClientChannel::finish(struct evhttp_request* req) {
110 assert(!completionQueue_.empty());
111 Completion completion = completionQueue_.front();
112 completionQueue_.pop();
113 if (req == nullptr) {
114 try {
115 completion.first();
116 } catch (const TTransportException& e) {
117 if (e.getType() == TTransportException::END_OF_FILE)
118 throw TException("connect failed");
119 else
120 throw;
121 }
122 return;
123 } else if (req->response_code != 200) {
124 try {
125 completion.first();
126 } catch (const TTransportException& e) {
127 std::stringstream ss;
128 ss << "server returned code " << req->response_code;
129 if (req->response_code_line)
130 ss << ": " << req->response_code_line;
131 if (e.getType() == TTransportException::END_OF_FILE)
132 throw TException(ss.str());
133 else
134 throw;
135 }
136 return;
137 }
138 completion.second->resetBuffer(EVBUFFER_DATA(req->input_buffer),
139 static_cast<uint32_t>(EVBUFFER_LENGTH(req->input_buffer)));
140 completion.first();
141 return;
142 }
143
144 /* static */ void TEvhttpClientChannel::response(struct evhttp_request* req, void* arg) {
145 auto* self = (TEvhttpClientChannel*)arg;
146 try {
147 self->finish(req);
148 } catch (std::exception& e) {
149 // don't propagate a C++ exception in C code (e.g. libevent)
150 std::cerr << "TEvhttpClientChannel::response exception thrown (ignored): " << e.what()
151 << std::endl;
152 }
153 }
154 }
155 }
156 } // apache::thrift::async