TensorFlow Serving C++ API Documentation
ev_fetch_client.cc
1 /* Copyright 2018 Google Inc. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7  http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 
16 #include <sys/types.h>
17 
18 #include <cstdio>
19 #include <cstdlib>
20 #include <cstring>
21 
22 #include "libevent/include/event2/buffer.h"
23 #include "libevent/include/event2/bufferevent.h"
24 #include "libevent/include/event2/event.h"
25 #include "libevent/include/event2/http.h"
26 #include "libevent/include/event2/keyvalq_struct.h"
27 #include "libevent/include/event2/util.h"
28 
29 namespace {
30 
31 struct event_base* ev_base;
32 struct evhttp_uri* http_uri;
33 struct evhttp_connection* evcon;
34 
35 void response_cb(struct evhttp_request* req, void* ctx) {
36  char buffer[1024];
37  int nread;
38 
39  if (req == nullptr) {
40  int errcode = EVUTIL_SOCKET_ERROR();
41  fprintf(stderr, "socket error = %s (%d)\n",
42  evutil_socket_error_to_string(errcode), errcode);
43  return;
44  }
45 
46  fprintf(stderr, "Response line: %d %s\n",
47  evhttp_request_get_response_code(req),
48  evhttp_request_get_response_code_line(req));
49 
50  struct evkeyvalq* headers = evhttp_request_get_input_headers(req);
51  struct evkeyval* header;
52  for (header = headers->tqh_first; header; header = header->next.tqe_next) {
53  fprintf(stderr, "%s : %s\n", header->key, header->value);
54  }
55 
56  while ((nread = evbuffer_remove(evhttp_request_get_input_buffer(req), buffer,
57  sizeof(buffer))) > 0) {
58  fwrite(buffer, static_cast<size_t>(nread), 1, stderr);
59  }
60 }
61 
62 void help() { fputs("Usage: ev_fetch-client uri [body]\n", stderr); }
63 
64 void err(const char* msg) { fputs(msg, stderr); }
65 
66 void cleanup() {
67  if (evcon != nullptr) {
68  evhttp_connection_free(evcon);
69  }
70  if (http_uri != nullptr) {
71  evhttp_uri_free(http_uri);
72  }
73 
74  event_base_free(ev_base);
75 }
76 
77 } // namespace
78 
79 int main(int argc, char** argv) {
80  fprintf(stdout, "Start the http client ...\n");
81 
82  if (argc < 2 || argc > 3) {
83  help();
84  return 1;
85  }
86 
87  const char* url = argv[1];
88 
89  const char* body = nullptr;
90 
91  if (argc == 3) {
92  body = argv[2];
93  }
94 
95  http_uri = evhttp_uri_parse(url);
96  if (http_uri == nullptr) {
97  err("malformed url");
98  return 1;
99  }
100 
101  const char* scheme = evhttp_uri_get_scheme(http_uri);
102  if (scheme == nullptr || strcasecmp(scheme, "http") != 0) {
103  err("url must be http");
104  return 1;
105  }
106 
107  const char* host = evhttp_uri_get_host(http_uri);
108  if (host == nullptr) {
109  err("url must have a host");
110  return 1;
111  }
112 
113  int port = evhttp_uri_get_port(http_uri);
114  if (port == -1) {
115  port = (strcasecmp(scheme, "http") == 0) ? 80 : 443;
116  }
117 
118  const char* path = evhttp_uri_get_path(http_uri);
119  if (strlen(path) == 0) {
120  path = "/";
121  }
122 
123  char uri[256];
124  const char* query = evhttp_uri_get_query(http_uri);
125  if (query == nullptr) {
126  snprintf(uri, sizeof(uri) - 1, "%s", path);
127  } else {
128  snprintf(uri, sizeof(uri) - 1, "%s?%s", path, query);
129  }
130  uri[sizeof(uri) - 1] = '\0';
131 
132  // Create event base
133  ev_base = event_base_new();
134  if (ev_base == nullptr) {
135  perror("event_base_new()");
136  return 1;
137  }
138 
139  // struct bufferevent* bev =
140  // bufferevent_socket_new(ev_base, -1, BEV_OPT_CLOSE_ON_FREE);
141  //
142  // if (bev == nullptr) {
143  // fprintf(stderr, "bufferevent_socket_new() failed\n");
144  // return 1;
145  // }
146 
147  // blocking call (DNS resolution)
148  evcon = evhttp_connection_base_bufferevent_new(
149  ev_base, nullptr, nullptr, host, static_cast<uint16_t>(port));
150  if (evcon == nullptr) {
151  fprintf(stderr, "evhttp_connection_base_bufferevent_new() failed\n");
152  return 1;
153  }
154 
155  int retries = 0;
156  evhttp_connection_set_retries(evcon, retries);
157 
158  int timeout_in_secs = 5;
159  evhttp_connection_set_timeout(evcon, timeout_in_secs);
160 
161  struct evhttp_request* req = evhttp_request_new(response_cb, evcon);
162  if (req == nullptr) {
163  fprintf(stderr, "evhttp_request_new() failed\n");
164  return 1;
165  }
166 
167  struct evkeyvalq* output_headers = evhttp_request_get_output_headers(req);
168  evhttp_add_header(output_headers, "Host", host);
169  evhttp_add_header(output_headers, "Connection", "close");
170 
171  if (body) {
172  struct evbuffer* output_buffer = evhttp_request_get_output_buffer(req);
173  size_t size = strlen(body);
174 
175  evbuffer_add(output_buffer, body, size);
176 
177  char length_header[8];
178  evutil_snprintf(length_header, sizeof(length_header) - 1, "%lu", size);
179  evhttp_add_header(output_headers, "Content-Length", length_header);
180  }
181 
182  int r = evhttp_make_request(evcon, req,
183  body ? EVHTTP_REQ_POST : EVHTTP_REQ_GET, uri);
184  if (r != 0) {
185  fprintf(stderr, "evhttp_make_request() failed\n");
186  return 1;
187  }
188 
189  event_base_dispatch(ev_base);
190 
191  cleanup();
192 
193  return 0;
194 }