18 #include "tensorflow_serving/util/net_http/server/internal/evhttp_request.h"
32 #include "absl/strings/match.h"
33 #include "absl/strings/string_view.h"
34 #include "absl/types/span.h"
35 #include "libevent/include/event2/buffer.h"
36 #include "libevent/include/event2/event.h"
37 #include "libevent/include/event2/http.h"
38 #include "libevent/include/event2/keyvalq_struct.h"
39 #include "tensorflow_serving/util/net_http/compression/gzip_zlib.h"
40 #include "tensorflow_serving/util/net_http/internal/net_logging.h"
41 #include "tensorflow_serving/util/net_http/public/header_names.h"
43 namespace tensorflow {
47 ParsedEvRequest::~ParsedEvRequest() {
49 evhttp_uri_free(decoded_uri);
52 if (request && evhttp_request_is_owned(request)) {
53 evhttp_request_free(request);
57 ParsedEvRequest::ParsedEvRequest(evhttp_request* request_in)
58 : request(request_in) {}
60 bool ParsedEvRequest::decode() {
61 switch (evhttp_request_get_command(request)) {
74 case EVHTTP_REQ_DELETE:
77 case EVHTTP_REQ_OPTIONS:
80 case EVHTTP_REQ_TRACE:
83 case EVHTTP_REQ_CONNECT:
86 case EVHTTP_REQ_PATCH:
93 uri = evhttp_request_get_uri(request);
95 decoded_uri = evhttp_uri_parse(uri);
96 if (decoded_uri ==
nullptr) {
101 path = evhttp_uri_get_path(decoded_uri);
102 if (path ==
nullptr) {
106 path_and_query = path;
107 const char* query = evhttp_uri_get_query(decoded_uri);
108 if (query !=
nullptr) {
109 path_and_query.push_back(
'?');
110 path_and_query.append(query);
113 const char* fragment = evhttp_uri_get_fragment(decoded_uri);
114 if (fragment !=
nullptr) {
115 path_and_query.push_back(
'#');
116 path_and_query.append(fragment);
119 headers = evhttp_request_get_input_headers(request);
124 EvHTTPRequest::EvHTTPRequest(std::unique_ptr<ParsedEvRequest> request,
125 ServerSupport* server)
127 parsed_request_(std::move(request)),
128 output_buf(nullptr) {}
130 EvHTTPRequest::~EvHTTPRequest() {
131 if (output_buf !=
nullptr) {
132 evbuffer_free(output_buf);
136 absl::string_view EvHTTPRequest::uri_path()
const {
137 return parsed_request_->path_and_query;
140 absl::string_view EvHTTPRequest::http_method()
const {
141 return parsed_request_->method;
144 bool EvHTTPRequest::Initialize() {
145 output_buf = evbuffer_new();
146 return output_buf !=
nullptr;
149 void EvHTTPRequest::WriteResponseBytes(
const char* data, int64_t size) {
151 if (output_buf ==
nullptr) {
152 NET_LOG(FATAL,
"Request not initialized.");
156 int ret = evbuffer_add(output_buf, data,
static_cast<size_t>(size));
158 NET_LOG(ERROR,
"Failed to write %zu bytes data to output buffer",
159 static_cast<size_t>(size));
163 void EvHTTPRequest::WriteResponseString(absl::string_view data) {
164 WriteResponseBytes(data.data(),
static_cast<int64_t
>(data.size()));
167 std::unique_ptr<char[], ServerRequestInterface::BlockDeleter>
168 EvHTTPRequest::ReadRequestBytes(int64_t* size) {
169 evbuffer* input_buf =
170 evhttp_request_get_input_buffer(parsed_request_->request);
171 if (input_buf ==
nullptr) {
177 if (evbuffer_get_length(input_buf) == 0) {
183 if (NeedUncompressGzipContent()) {
184 return ReadRequestGzipBytes(input_buf, size);
187 auto buf_size =
reinterpret_cast<size_t*
>(size);
189 *buf_size = evbuffer_get_contiguous_space(input_buf);
190 assert(*buf_size > 0);
192 char* block = std::allocator<char>().allocate(*buf_size);
193 int ret = evbuffer_remove(input_buf, block, *buf_size);
195 if (ret != *buf_size) {
196 NET_LOG(ERROR,
"Unexpected: read less than specified num_bytes : %zu",
198 std::allocator<char>().deallocate(block, *buf_size);
203 return std::unique_ptr<char[], ServerRequestInterface::BlockDeleter>(
204 block, ServerRequestInterface::BlockDeleter(*buf_size));
207 std::unique_ptr<char[], ServerRequestInterface::BlockDeleter>
208 EvHTTPRequest::ReadRequestGzipBytes(evbuffer* input_buf, int64_t* size) {
209 std::vector<absl::Span<char>> buf_list;
211 size_t body_length = 0;
213 auto buf_size = evbuffer_get_contiguous_space(input_buf);
219 char* block = std::allocator<char>().allocate(buf_size);
220 int ret = evbuffer_remove(input_buf, block, buf_size);
221 if (ret != buf_size) {
222 NET_LOG(ERROR,
"Unexpected: read less than specified num_bytes : %zu",
224 std::allocator<char>().deallocate(block, buf_size);
225 for (
auto buf : buf_list) {
226 std::allocator<char>().deallocate(buf.data(), buf.size());
232 body_length += buf_size;
233 buf_list.emplace_back(block, buf_size);
236 char* comp_body = std::allocator<char>().allocate(body_length);
239 for (
auto buf : buf_list) {
240 memcpy(comp_body + pos, buf.data(), buf.size());
242 std::allocator<char>().deallocate(buf.data(), buf.size());
246 auto uncomp_size =
reinterpret_cast<size_t*
>(size);
247 UncompressGzipBody(comp_body, body_length,
248 reinterpret_cast<void**
>(&uncomp_body), uncomp_size);
250 std::allocator<char>().deallocate(comp_body, body_length);
252 if (uncomp_body !=
nullptr) {
253 return std::unique_ptr<char[], ServerRequestInterface::BlockDeleter>(
254 uncomp_body, ServerRequestInterface::BlockDeleter(*uncomp_size));
256 NET_LOG(ERROR,
"Failed to uncompress the gzipped body");
262 bool EvHTTPRequest::NeedUncompressGzipContent() {
263 if (handler_options_ !=
nullptr &&
264 handler_options_->auto_uncompress_input()) {
265 auto content_encoding = GetRequestHeader(HTTPHeaders::CONTENT_ENCODING);
266 return absl::StrContains(content_encoding,
"gzip");
272 void EvHTTPRequest::UncompressGzipBody(
void* input,
size_t input_size,
273 void** uncompressed_input,
274 size_t* uncompressed_input_size) {
275 int64_t max = handler_options_->auto_uncompress_max_size() > 0
276 ? handler_options_->auto_uncompress_max_size()
277 : ZLib::kMaxUncompressedBytes;
280 *uncompressed_input_size =
static_cast<size_t>(max);
283 int err = zlib.UncompressGzipAndAllocate(
284 reinterpret_cast<Bytef**
>(uncompressed_input),
285 reinterpret_cast<uLongf*
>(uncompressed_input_size),
286 static_cast<Bytef*
>(input),
static_cast<uLong
>(input_size));
288 NET_LOG(ERROR,
"Got zlib error: %d", err);
294 absl::string_view EvHTTPRequest::GetRequestHeader(
295 absl::string_view header)
const {
296 std::string header_str(header.data(), header.size());
297 return absl::NullSafeStringView(
298 evhttp_find_header(parsed_request_->headers, header_str.c_str()));
301 std::vector<absl::string_view> EvHTTPRequest::request_headers()
const {
302 auto result = std::vector<absl::string_view>();
303 auto ev_headers = parsed_request_->headers;
305 for (evkeyval* header = ev_headers->tqh_first; header;
306 header = header->next.tqe_next) {
307 result.emplace_back(header->key);
313 void EvHTTPRequest::OverwriteResponseHeader(absl::string_view header,
314 absl::string_view value) {
315 evkeyvalq* ev_headers =
316 evhttp_request_get_output_headers(parsed_request_->request);
318 std::string header_str = std::string(header.data(), header.size());
319 const char* header_cstr = header_str.c_str();
321 evhttp_remove_header(ev_headers, header_cstr);
322 evhttp_add_header(ev_headers, header_cstr,
323 std::string(value.data(), value.size()).c_str());
326 void EvHTTPRequest::AppendResponseHeader(absl::string_view header,
327 absl::string_view value) {
328 evkeyvalq* ev_headers =
329 evhttp_request_get_output_headers(parsed_request_->request);
331 int ret = evhttp_add_header(ev_headers,
332 std::string(header.data(), header.size()).c_str(),
333 std::string(value.data(), value.size()).c_str());
337 "Unexpected: failed to set the request header"
339 static_cast<int>(header.size()), header.data(),
340 static_cast<int>(value.size()), value.data());
344 void EvHTTPRequest::PartialReplyWithStatus(HTTPStatusCode status) {
345 NET_LOG(FATAL,
"PartialReplyWithStatus not implemented.");
348 void EvHTTPRequest::PartialReply() {
349 NET_LOG(FATAL,
"PartialReplyWithStatus not implemented.");
352 ServerRequestInterface::CallbackStatus
353 EvHTTPRequest::PartialReplyWithFlushCallback(std::function<
void()> callback) {
354 NET_LOG(FATAL,
"PartialReplyWithStatus not implemented.");
355 return CallbackStatus::NOT_SCHEDULED;
358 void EvHTTPRequest::ReplyWithStatus(HTTPStatusCode status) {
360 server_->EventLoopSchedule([
this, status]() { EvSendReply(status); });
363 NET_LOG(ERROR,
"Failed to EventLoopSchedule ReplyWithStatus()");
370 void EvHTTPRequest::EvSendReply(HTTPStatusCode status) {
371 evhttp_send_reply(parsed_request_->request,
static_cast<int>(status),
nullptr,
377 void EvHTTPRequest::Reply() { ReplyWithStatus(HTTPStatusCode::OK); }
381 void EvHTTPRequest::Abort() {
382 evhttp_send_error(parsed_request_->request, HTTP_INTERNAL,
nullptr);