18 #include "tensorflow_serving/util/net_http/client/test_client/internal/evhttp_connection.h"
24 #include "absl/strings/str_cat.h"
25 #include "tensorflow_serving/util/net_http/internal/net_logging.h"
26 #include "tensorflow_serving/util/net_http/public/response_code_enum.h"
28 namespace tensorflow {
32 TestEvHTTPConnection::~TestEvHTTPConnection() {
33 if (evcon_ !=
nullptr) {
34 evhttp_connection_free(evcon_);
36 if (http_uri_ !=
nullptr) {
37 evhttp_uri_free(http_uri_);
40 event_base_free(ev_base_);
44 void TestEvHTTPConnection::Terminate() {
45 event_base_loopexit(ev_base_,
nullptr);
46 if (loop_exit_ !=
nullptr) {
47 loop_exit_->WaitForNotification();
51 std::unique_ptr<TestEvHTTPConnection> TestEvHTTPConnection::Connect(
52 absl::string_view url) {
53 std::string url_str(url.data(), url.size());
54 struct evhttp_uri* http_uri = evhttp_uri_parse(url_str.c_str());
55 if (http_uri ==
nullptr) {
56 NET_LOG(ERROR,
"Failed to connect : event_base_new()");
60 const char* host = evhttp_uri_get_host(http_uri);
61 if (host ==
nullptr) {
62 NET_LOG(ERROR,
"url must have a host %.*s",
static_cast<int>(url.size()),
67 int port = evhttp_uri_get_port(http_uri);
72 auto result = Connect(host, port);
73 evhttp_uri_free(http_uri);
78 std::unique_ptr<TestEvHTTPConnection> TestEvHTTPConnection::Connect(
79 absl::string_view host,
int port) {
80 std::unique_ptr<TestEvHTTPConnection> result(
new TestEvHTTPConnection());
82 result->ev_base_ = event_base_new();
83 if (result->ev_base_ ==
nullptr) {
84 NET_LOG(ERROR,
"Failed to connect : event_base_new()");
89 std::string host_str(host.data(), host.size());
90 result->evcon_ = evhttp_connection_base_bufferevent_new(
91 result->ev_base_,
nullptr,
nullptr, host_str.c_str(),
92 static_cast<uint16_t
>(port));
93 if (result->evcon_ ==
nullptr) {
95 "Failed to connect : evhttp_connection_base_bufferevent_new()");
99 evhttp_connection_set_retries(result->evcon_, 0);
102 evhttp_connection_set_timeout(result->evcon_, 5);
110 void PopulateResponse(evhttp_request* req, TestClientResponse* response) {
112 static_cast<HTTPStatusCode
>(evhttp_request_get_response_code(req));
114 struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
115 struct evkeyval* header;
116 for (header = headers->tqh_first; header; header = header->next.tqe_next) {
117 response->headers.emplace_back(header->key, header->value);
123 while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req), buffer,
124 sizeof(buffer))) > 0) {
125 absl::StrAppend(&response->body,
126 absl::string_view(buffer,
static_cast<size_t>(nread)));
130 evhttp_cmd_type GetMethodEnum(absl::string_view method,
bool with_body) {
131 if (method.compare(
"GET") == 0) {
132 return EVHTTP_REQ_GET;
133 }
else if (method.compare(
"POST") == 0) {
134 return EVHTTP_REQ_POST;
135 }
else if (method.compare(
"HEAD") == 0) {
136 return EVHTTP_REQ_HEAD;
137 }
else if (method.compare(
"PUT") == 0) {
138 return EVHTTP_REQ_PUT;
139 }
else if (method.compare(
"DELETE") == 0) {
140 return EVHTTP_REQ_DELETE;
141 }
else if (method.compare(
"OPTIONS") == 0) {
142 return EVHTTP_REQ_OPTIONS;
143 }
else if (method.compare(
"TRACE") == 0) {
144 return EVHTTP_REQ_TRACE;
145 }
else if (method.compare(
"CONNECT") == 0) {
146 return EVHTTP_REQ_CONNECT;
147 }
else if (method.compare(
"PATCH") == 0) {
148 return EVHTTP_REQ_PATCH;
151 return EVHTTP_REQ_POST;
153 return EVHTTP_REQ_GET;
158 void ResponseDone(evhttp_request* req,
void* ctx) {
159 TestClientResponse* response =
reinterpret_cast<TestClientResponse*
>(ctx);
161 if (req ==
nullptr) {
163 int errcode = EVUTIL_SOCKET_ERROR();
164 NET_LOG(ERROR,
"socket error = %s (%d)",
165 evutil_socket_error_to_string(errcode), errcode);
169 PopulateResponse(req, response);
171 if (response->done !=
nullptr) {
177 bool GenerateEvRequest(evhttp_connection* evcon,
178 const TestClientRequest& request,
179 TestClientResponse* response) {
180 evhttp_request* evreq = evhttp_request_new(ResponseDone, response);
181 if (evreq ==
nullptr) {
182 NET_LOG(ERROR,
"Failed to send request : evhttp_request_new()");
186 evkeyvalq* output_headers = evhttp_request_get_output_headers(evreq);
187 for (
auto header : request.headers) {
188 std::string key(header.first.data(), header.first.size());
189 std::string value(header.second.data(), header.second.size());
190 evhttp_add_header(output_headers, key.c_str(), value.c_str());
193 evhttp_add_header(output_headers,
"Connection",
"close");
195 if (!request.body.empty()) {
196 evbuffer* output_buffer = evhttp_request_get_output_buffer(evreq);
198 std::string body(request.body.data(), request.body.size());
199 evbuffer_add(output_buffer, body.c_str(), request.body.size());
201 char length_header[16];
202 evutil_snprintf(length_header,
sizeof(length_header) - 1,
"%lu",
203 request.body.size());
204 evhttp_add_header(output_headers,
"Content-Length", length_header);
207 std::string uri(request.uri_path.data(), request.uri_path.size());
208 int r = evhttp_make_request(
209 evcon, evreq, GetMethodEnum(request.method, !request.body.empty()),
212 NET_LOG(ERROR,
"evhttp_make_request() failed");
222 bool TestEvHTTPConnection::BlockingSendRequest(
const TestClientRequest& request,
223 TestClientResponse* response) {
224 if (!GenerateEvRequest(evcon_, request, response)) {
225 NET_LOG(ERROR,
"Failed to generate the ev_request");
230 event_base_dispatch(ev_base_);
234 bool TestEvHTTPConnection::SendRequest(
const TestClientRequest& request,
235 TestClientResponse* response) {
236 if (this->executor_ ==
nullptr) {
237 NET_LOG(ERROR,
"EventExecutor is not configured.");
241 if (!GenerateEvRequest(evcon_, request, response)) {
242 NET_LOG(ERROR,
"Failed to generate the ev_request");
246 executor_->Schedule([
this]() {
247 loop_exit_.reset(
new absl::Notification());
248 event_base_dispatch(ev_base_);
249 loop_exit_->Notify();
255 void TestEvHTTPConnection::SetExecutor(
256 std::unique_ptr<EventExecutor> executor) {
257 this->executor_ = std::move(executor);