OpenSDN source code
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
http_curl.cc
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
4  *
5  * This software is licensed as described in the file COPYING, which
6  * you should have received as part of this distribution. The terms
7  * are also available at http://curl.haxx.se/docs/copyright.html.
8  *
9  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
10  * copies of the Software, and permit persons to whom the Software is
11  * furnished to do so, under the terms of the COPYING file.
12  *
13  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
14  * KIND, either express or implied.
15  *
16  ***************************************************************************/
17 
18 /*
19  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
20  */
21 
22 #include "http_client.h"
23 #include "http_curl.h"
24 #include <curl/curl.h>
25 #include <boost/asio.hpp>
26 #include <boost/bind.hpp>
27 #include <boost/intrusive_ptr.hpp>
28 #include <tbb/mutex.h>
29 
30 #define MSG_OUT stdout /* Send info to stdout, change to stderr if you want */
31 
32 using tbb::mutex;
33 
35 
36 /* Update the event timer after curl_multi library calls */
37 static int multi_timer_cb(CURLM *multi, long timeout_ms, HttpClient *client)
38 {
39 
40  if ( timeout_ms > 0 )
41  {
42  client->StartTimer(timeout_ms);
43  }
44  else
45  {
46  client->CancelTimer();
47  timer_cb(client->GlobalInfo());
48  }
49 
50  return 0;
51 }
52 
53 /* Die if we get a bad CURLMcode somewhere */
54 static void mcode_or_die(const char *where, CURLMcode code)
55 {
56  if ( CURLM_OK != code )
57  {
58  const char *s;
59  switch ( code )
60  {
61  case CURLM_CALL_MULTI_PERFORM: s="CURLM_CALL_MULTI_PERFORM"; break;
62  case CURLM_BAD_HANDLE: s="CURLM_BAD_HANDLE"; break;
63  case CURLM_BAD_EASY_HANDLE: s="CURLM_BAD_EASY_HANDLE"; break;
64  case CURLM_OUT_OF_MEMORY: s="CURLM_OUT_OF_MEMORY"; break;
65  case CURLM_INTERNAL_ERROR: s="CURLM_INTERNAL_ERROR"; break;
66  case CURLM_UNKNOWN_OPTION: s="CURLM_UNKNOWN_OPTION"; break;
67  case CURLM_LAST: s="CURLM_LAST"; break;
68  case CURLM_BAD_SOCKET: s="CURLM_BAD_SOCKET"; break;
69  default: s="CURLM_unknown"; break;
70  }
71 
72  fprintf(MSG_OUT, "\nERROR: %s returns %s", where, s);
73  }
74 }
75 
76 /* Check for completed transfers, and remove their easy handles */
78 {
79  char *eff_url;
80  CURLMsg *msg;
81  int msgs_left;
82  ConnInfo *conn;
83  CURL *easy;
84  CURLcode res;
85 
86  while ((msg = curl_multi_info_read(g->multi, &msgs_left)))
87  {
88  if (msg->msg == CURLMSG_DONE)
89  {
90  easy = msg->easy_handle;
91  res = msg->data.result;
92  curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
93  curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
94 
95  if (conn) {
96  boost::system::error_code error(res, curl_error_category);
97  std::string empty_str("");
98  if (conn->connection->HttpClientCb() != NULL)
99  conn->connection->HttpClientCb()(empty_str, error);
100  }
101  }
102  }
103 }
104 
105 typedef boost::intrusive_ptr<HttpClientSession> TcpSessionPtr;
106 
107 static void event_cb_impl(GlobalInfo *g, TcpSessionPtr session, int action,
108  const boost::system::error_code &error,
109  std::size_t bytes_transferred)
110 {
111 
112  if (session->IsClosed()) return;
113 
114  if (g->client->IsErrorHard(error)) return;
115 
116  CURLMcode rc;
117  rc = curl_multi_socket_action(g->multi, session->socket()->native_handle(), action, &g->still_running);
118 
119  mcode_or_die("event_cb: curl_multi_socket_action", rc);
120  check_multi_info(g);
121 
122  if ( g->still_running <= 0 )
123  {
124  g->client->CancelTimer();
125  }
126 }
127 
128 /* Called by asio when there is an action on a socket */
129 static void event_cb(GlobalInfo *g, TcpSessionPtr session, int action,
130  const boost::system::error_code &error, std::size_t bytes_transferred)
131 {
132  tbb::mutex::scoped_lock lock(session->mutex());
133 
134  // Ignore if the connection is already deleted.
135  if (!session->Connection()) return;
136 
137  HttpClient *client = session->Connection()->client();
138  // Ignore if httpclient is null when we get this from meta_data args from VM
139  if (!client) {
140  LOG(ERROR,"HttpClient:unable to call ProcessEvent() as HttpClient is NULL" <<
141  ", session :" << session <<
142  ", session->Connection(): " << session->Connection() <<
143  ", HttpClient :" << session->Connection()->client());
144  return;
145  }
146 
147  client->ProcessEvent(boost::bind(&event_cb_impl, g, session, action, error,
148  bytes_transferred));
149 }
150 
151 /* Called by asio when our timeout expires */
153 {
154  CURLMcode rc;
155  rc = curl_multi_socket_action(g->multi, CURL_SOCKET_TIMEOUT, 0, &g->still_running);
156  mcode_or_die("timer_cb: curl_multi_socket_action", rc);
157 
158  // When timeout happens, call multi_perform to check if we still have
159  // pending handles; if yes, continue running the timer
160  rc = curl_multi_perform(g->multi, &g->still_running);
161  mcode_or_die("timer_cb: curl_multi_perform", rc);
162 
163  check_multi_info(g);
164  return (g->still_running > 0);
165 }
166 
167 /* Clean up any data */
168 static void remsock(SockInfo *sock_info, GlobalInfo *g)
169 {
170  if ( sock_info )
171  {
172  free(sock_info);
173  }
174 }
175 
176 static bool setsock(SockInfo *sock_info, curl_socket_t s, CURL*e, int act, GlobalInfo *g)
177 {
178  if (!sock_info || !sock_info->conn_info || !sock_info->conn_info->connection)
179  {
180  return false;
181  }
182 
183  HttpClientSession *session = sock_info->conn_info->connection->session();
184  if (!session || session->IsClosed())
185  return false;
186 
187  boost::asio::ip::tcp::socket * tcp_socket = session->socket();
188 
189  sock_info->action = act;
190 
191  if ( act == CURL_POLL_IN )
192  {
193  tcp_socket->async_read_some(boost::asio::null_buffers(),
194  boost::bind(&event_cb, g, TcpSessionPtr(session),
195  act, _1, _2));
196  }
197  else if ( act == CURL_POLL_OUT )
198  {
199  tcp_socket->async_write_some(boost::asio::null_buffers(),
200  boost::bind(&event_cb, g, TcpSessionPtr(session),
201  act, _1, _2));
202  }
203  else if ( act == CURL_POLL_INOUT )
204  {
205  tcp_socket->async_read_some(boost::asio::null_buffers(),
206  boost::bind(&event_cb, g, TcpSessionPtr(session),
207  act, _1, _2));
208  tcp_socket->async_write_some(boost::asio::null_buffers(),
209  boost::bind(&event_cb, g, TcpSessionPtr(session),
210  act, _1, _2));
211  }
212  return true;
213 }
214 
215 
216 static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
217 {
218  // store socket details in SockInfo
219  SockInfo *sock_info = (SockInfo *)calloc(sizeof(SockInfo), 1);
220  curl_easy_getinfo(easy, CURLINFO_PRIVATE, &sock_info->conn_info);
221 
222  if (!setsock(sock_info, s, easy, action, g)) {
223  free(sock_info);
224  return;
225  }
226 
227  curl_multi_assign(g->multi, s, sock_info);
228 }
229 
230 /* CURLMOPT_SOCKETFUNCTION */
231 static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
232 {
233  GlobalInfo *g = (GlobalInfo*) cbp;
234  SockInfo *sock_info = (SockInfo *)sockp;
235 
236  if ( what == CURL_POLL_REMOVE )
237  {
238  remsock(sock_info, g);
239  }
240  else
241  {
242  if ( !sockp )
243  {
244  addsock(s, e, what, g);
245  }
246  else
247  {
248  setsock(sock_info, s, e, what, g);
249  }
250  }
251  return 0;
252 }
253 
254 
255 /* CURLOPT_WRITEFUNCTION */
256 static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
257 {
258  size_t written = size * nmemb;
259 
260  HttpConnection *conn = static_cast<HttpConnection *>(data);
261  conn->AssignData((char *)ptr, written);
262  return written;
263 }
264 
265 /* CURLOPT_HEADERFUNCTION */
266 static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data)
267 {
268  size_t written = size * nmemb;
269 
270  HttpConnection *conn = static_cast<HttpConnection *>(data);
271  conn->AssignHeader((char *)ptr, written);
272  return written;
273 }
274 
275 static size_t read_cb(void *ptr, size_t size, size_t nmemb, void *data)
276 {
277  HttpConnection *conn = static_cast<HttpConnection *>(data);
278  ConnInfo *curl_handle = conn->curl_handle();
279  char *str = curl_handle->post;
280 
281  size_t maxb = size*nmemb;
282  size_t offset = conn->GetOffset();
283  size_t datasize = 0;
284  if (curl_handle->post_len > offset)
285  datasize = curl_handle->post_len - offset;
286 
287  if (maxb >= datasize) {
288  memcpy(ptr, str + offset, datasize);
289  conn->UpdateOffset(datasize);
290  return datasize;
291  } else {
292  memcpy(ptr, str + offset, maxb);
293  conn->UpdateOffset(maxb);
294  return maxb;
295  }
296 
297  return 0;
298 }
299 
300 
301 /* CURLOPT_PROGRESSFUNCTION */
302 static int prog_cb (void *p, double dltotal, double dlnow, double ult,
303  double uln)
304 {
305  (void)ult;
306  (void)uln;
307 
308  return 0;
309 }
310 
311 /* CURLOPT_OPENSOCKETFUNCTION */
312 static curl_socket_t open_socket(void *data,
313  curlsocktype purpose,
314  struct curl_sockaddr *address)
315 {
316  HttpConnection *conn = static_cast<HttpConnection *>(data);
317 
318  curl_socket_t sockfd = CURL_SOCKET_BAD;
319 
320  /* restrict to ipv4 */
321  if (purpose == CURLSOCKTYPE_IPCXN && address->family == AF_INET)
322  {
323  HttpClientSession *session = conn->CreateSession();
324  if (session) {
325  sockfd = session->socket()->native_handle();
326  conn->set_session(session);
327  }
328  }
329 
330  return sockfd;
331 }
332 
333 /* CURLOPT_CLOSESOCKETFUNCTION */
334 static int close_socket(void *clientp, curl_socket_t item)
335 {
336  HttpConnection *conn = static_cast<HttpConnection *>(clientp);
337  conn->delete_session();
338  return 0;
339 }
340 
341 static int send_perform(ConnInfo *conn, GlobalInfo *g) {
342  // add the handle
343  CURLMcode m_rc = curl_multi_add_handle(g->multi, conn->easy);
344  if (m_rc != CURLM_OK)
345  return m_rc;
346 
347  // start sending data rightaway; use timer to re-invoke multi_perform
348  int counter = 0;
349  CURLMcode rc = curl_multi_perform(g->multi, &counter);
350  if (rc == CURLM_OK && counter <= 0) {
351  // send done; invoke callback to indicate this
352  if (conn->connection && conn->connection->session()) {
353  const boost::system::error_code ec;
354  event_cb(g, TcpSessionPtr(conn->connection->session()), 0, ec, 0);
355  }
356  } else {
357  // start timer and check for send completion on timeout
359  }
360 
361  return rc;
362 }
363 
364 void del_conn(HttpConnection *connection, GlobalInfo *g) {
365 
366  if (connection->session()) {
367  tbb::mutex::scoped_lock lock(connection->session()->mutex());
368  connection->session()->SetConnection(NULL);
369  }
370 
371  struct _ConnInfo *curl_handle = connection->curl_handle();
372  if (curl_handle) {
373  connection->set_curl_handle(NULL);
374  del_curl_handle(curl_handle, g);
375  }
376 }
377 
378 void del_curl_handle(ConnInfo *curl_handle, GlobalInfo *g) {
379  if (curl_handle) {
380  curl_easy_setopt(curl_handle->easy, CURLOPT_PRIVATE, NULL);
381  curl_multi_remove_handle(g->multi, curl_handle->easy);
382  curl_slist_free_all(curl_handle->headers);
383  free(curl_handle->post);
384  free(curl_handle->url);
385  curl_easy_cleanup(curl_handle->easy);
386  free(curl_handle);
387  }
388 }
389 
390 /* Create a new easy handle, and add it to the global curl_multi */
392  bool header, bool short_timeout, bool reuse)
393 {
394  ConnInfo *conn = (ConnInfo *)calloc(1, sizeof(ConnInfo));
395  memset(conn, 0, sizeof(ConnInfo));
396  conn->error[CURL_ERROR_SIZE]='\0';
397 
398  conn->easy = curl_easy_init();
399 
400  if ( !conn->easy ) {
401  free(conn);
402  return NULL;
403  }
404  conn->global = g;
405  curl_easy_setopt(conn->easy, CURLOPT_FOLLOWLOCATION, 1L);
406  curl_easy_setopt(conn->easy, CURLOPT_WRITEFUNCTION, write_cb);
407  curl_easy_setopt(conn->easy, CURLOPT_WRITEDATA, connection);
408  curl_easy_setopt(conn->easy, CURLOPT_HEADERFUNCTION, header_cb);
409  curl_easy_setopt(conn->easy, CURLOPT_HEADERDATA, connection);
410  curl_easy_setopt(conn->easy, CURLOPT_READFUNCTION, read_cb);
411  curl_easy_setopt(conn->easy, CURLOPT_READDATA, connection);
412  curl_easy_setopt(conn->easy, CURLOPT_ERRORBUFFER, conn->error);
413  curl_easy_setopt(conn->easy, CURLOPT_PRIVATE, conn);
414  curl_easy_setopt(conn->easy, CURLOPT_NOPROGRESS, 1L);
415  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSFUNCTION, prog_cb);
416  curl_easy_setopt(conn->easy, CURLOPT_PROGRESSDATA, conn);
417  curl_easy_setopt(conn->easy, CURLOPT_CONNECTTIMEOUT, 4L); // in secs
418  if (short_timeout) {
419  /* set the timeout limits to abort the connection */
420  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 3L);
421  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
422  } else {
423  /* set longer timeout limits */
424  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_TIME, 30L);
425  curl_easy_setopt(conn->easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
426  }
427  curl_easy_setopt(conn->easy, CURLOPT_FORBID_REUSE, 1L);
428 
429  /* call this function to get a socket */
430  curl_easy_setopt(conn->easy, CURLOPT_OPENSOCKETFUNCTION, open_socket);
431  curl_easy_setopt(conn->easy, CURLOPT_OPENSOCKETDATA, connection);
432 
433  /* call this function to close a socket */
434  curl_easy_setopt(conn->easy, CURLOPT_CLOSESOCKETFUNCTION, close_socket);
435  curl_easy_setopt(conn->easy, CURLOPT_CLOSESOCKETDATA, connection);
436 
437  return conn;
438 }
439 
440 void set_url(ConnInfo *conn, const char *url) {
441  conn->url = strdup(url);
442  curl_easy_setopt(conn->easy, CURLOPT_URL, conn->url);
443 }
444 
445 void set_header_options(ConnInfo *conn, const char *options) {
446  conn->headers = curl_slist_append(conn->headers, options);
447  curl_easy_setopt(conn->easy, CURLOPT_HTTPHEADER, conn->headers);
448 }
449 
450 void set_ssl_options(ConnInfo *conn, const char *client_cert,
451  const char *client_cert_type, const char *client_key,
452  const char *ca_cert) {
453  curl_easy_setopt(conn->easy, CURLOPT_SSLCERT, client_cert);
454  curl_easy_setopt(conn->easy, CURLOPT_SSLCERTTYPE, client_cert_type);
455  curl_easy_setopt(conn->easy, CURLOPT_SSLKEY, client_key);
456  curl_easy_setopt(conn->easy, CURLOPT_CAINFO, ca_cert);
457  if (ca_cert[0] == '\0') {
458  // Disable certificate validation if CA certificate path doesnt exist
459  curl_easy_setopt(conn->easy, CURLOPT_SSL_VERIFYPEER, 0L);
460  curl_easy_setopt(conn->easy, CURLOPT_SSL_VERIFYHOST, 0L);
461  }
462 }
463 
464 void set_post_string(ConnInfo *conn, const char *post, uint32_t len) {
465  conn->post = (char *) malloc(len);
466  memcpy(conn->post, post, len);
467  conn->post_len = len;
468  curl_easy_setopt(conn->easy, CURLOPT_POST, 1);
469  curl_easy_setopt(conn->easy, CURLOPT_POSTFIELDS, conn->post);
470  curl_easy_setopt(conn->easy, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
471 }
472 
473 void set_put_string(ConnInfo *conn, const char *put, uint32_t len) {
474  conn->post = (char *) malloc(len);
475  memcpy(conn->post, put, len);
476  conn->post_len = len;
477  curl_easy_setopt(conn->easy, CURLOPT_UPLOAD, 1);
478  curl_easy_setopt(conn->easy, CURLOPT_PUT, 1);
479  curl_easy_setopt(conn->easy, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
480 }
481 
482 int http_get(ConnInfo *conn, GlobalInfo *g) {
483  CURLMcode rc = curl_multi_add_handle(g->multi, conn->easy);
484  return (int)rc;
485 }
486 
487 int http_head(ConnInfo *conn, GlobalInfo *g) {
488  curl_easy_setopt(conn->easy, CURLOPT_CUSTOMREQUEST, "HEAD");
489  CURLMcode rc = curl_multi_add_handle(g->multi, conn->easy);
490  return (int)rc;
491 }
492 
493 int http_put(ConnInfo *conn, GlobalInfo *g) {
494  return send_perform(conn, g);
495 }
496 
497 int http_post(ConnInfo *conn, GlobalInfo *g) {
498  return send_perform(conn, g);
499 }
500 
502  curl_easy_setopt(conn->easy, CURLOPT_CUSTOMREQUEST, "DELETE");
503  CURLMcode rc = curl_multi_add_handle(g->multi, conn->easy);
504  return (int)rc;
505 }
506 
507 int curl_init(HttpClient *client)
508 {
509  struct _GlobalInfo *g = client->GlobalInfo();
510 
511  memset(g, 0, sizeof(GlobalInfo));
512  g->multi = curl_multi_init();
513  g->client = client;
514 
515  curl_multi_setopt(g->multi, CURLMOPT_SOCKETFUNCTION, sock_cb);
516  curl_multi_setopt(g->multi, CURLMOPT_SOCKETDATA, g);
517  curl_multi_setopt(g->multi, CURLMOPT_TIMERFUNCTION, multi_timer_cb);
518  curl_multi_setopt(g->multi, CURLMOPT_TIMERDATA, client);
519 
520  return 0;
521 }
static int prog_cb(void *p, double dltotal, double dlnow, double ult, double uln)
Definition: http_curl.cc:302
static void remsock(SockInfo *sock_info, GlobalInfo *g)
Definition: http_curl.cc:168
void UpdateOffset(size_t bytes)
Definition: http_client.cc:365
tbb::mutex & mutex()
Definition: http_client.h:49
HttpCb HttpClientCb()
Definition: http_client.h:113
static void check_multi_info(GlobalInfo *g)
Definition: http_curl.cc:77
HttpClient * client
Definition: http_curl.h:26
static int send_perform(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:341
CURLM * multi
Definition: http_curl.h:24
void StartTimer(long)
Definition: http_client.cc:492
static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
Definition: http_curl.cc:256
int http_head(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:487
ConnInfo * conn_info
Definition: http_curl.h:45
int action
Definition: http_curl.h:44
static curl_socket_t open_socket(void *data, curlsocktype purpose, struct curl_sockaddr *address)
Definition: http_curl.cc:312
struct _GlobalInfo * GlobalInfo()
Definition: http_client.h:202
struct curl_slist * headers
Definition: http_curl.h:36
void ProcessEvent(EnqueuedCb cb)
Definition: http_client.cc:479
char * post
Definition: http_curl.h:34
GlobalInfo * global
Definition: http_curl.h:37
CURL * easy
Definition: http_curl.h:32
int http_delete(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:501
boost::intrusive_ptr< HttpClientSession > TcpSessionPtr
Definition: http_curl.cc:105
static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
Definition: http_curl.cc:231
HttpClientSession * session()
Definition: http_client.h:99
#define MSG_OUT
Definition: http_curl.cc:30
char * url
Definition: http_curl.h:33
HttpClientSession * CreateSession()
Definition: http_client.cc:108
static size_t read_cb(void *ptr, size_t size, size_t nmemb, void *data)
Definition: http_curl.cc:275
void CancelTimer()
Definition: http_client.cc:497
int curl_init(HttpClient *client)
Definition: http_curl.cc:507
HttpConnection * connection
Definition: http_curl.h:39
void set_put_string(ConnInfo *conn, const char *put, uint32_t len)
Definition: http_curl.cc:473
static bool setsock(SockInfo *sock_info, curl_socket_t s, CURL *e, int act, GlobalInfo *g)
Definition: http_curl.cc:176
int http_put(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:493
static Options options
static void mcode_or_die(const char *where, CURLMcode code)
Definition: http_curl.cc:54
void set_post_string(ConnInfo *conn, const char *post, uint32_t len)
Definition: http_curl.cc:464
static const uint32_t kDefaultTimeout
Definition: http_client.h:183
char error[CURL_ERROR_SIZE+1]
Definition: http_curl.h:38
void AssignData(const char *ptr, size_t size)
Definition: http_client.cc:306
int http_get(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:482
void del_curl_handle(ConnInfo *curl_handle, GlobalInfo *g)
Definition: http_curl.cc:378
void del_conn(HttpConnection *connection, GlobalInfo *g)
Definition: http_curl.cc:364
bool IsClosed() const
Definition: tcp_session.h:125
struct _ConnInfo * curl_handle()
Definition: http_client.h:96
static int close_socket(void *clientp, curl_socket_t item)
Definition: http_curl.cc:334
int http_post(ConnInfo *conn, GlobalInfo *g)
Definition: http_curl.cc:497
int still_running
Definition: http_curl.h:25
static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data)
Definition: http_curl.cc:266
bool IsErrorHard(const boost::system::error_code &ec)
Definition: http_client.cc:501
void set_header_options(ConnInfo *conn, const char *options)
Definition: http_curl.cc:445
void SetConnection(HttpConnection *conn)
Definition: http_client.h:47
void set_url(ConnInfo *conn, const char *url)
Definition: http_curl.cc:440
#define LOG(_Level, _Msg)
Definition: logging.h:33
uint32_t post_len
Definition: http_curl.h:35
void set_curl_handle(struct _ConnInfo *handle)
Definition: http_client.h:105
void set_ssl_options(ConnInfo *conn, const char *client_cert, const char *client_cert_type, const char *client_key, const char *ca_cert)
Definition: http_curl.cc:450
size_t GetOffset()
Definition: http_client.cc:369
bool timer_cb(GlobalInfo *g)
Definition: http_curl.cc:152
const CurlErrorCategory curl_error_category
Definition: http_curl.cc:34
ConnInfo * new_conn(HttpConnection *connection, GlobalInfo *g, bool header, bool short_timeout, bool reuse)
Definition: http_curl.cc:391
static int multi_timer_cb(CURLM *multi, long timeout_ms, HttpClient *client)
Definition: http_curl.cc:37
void set_session(HttpClientSession *session)
Definition: http_client.cc:129
static void event_cb(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: http_curl.cc:129
virtual Socket * socket() const
Definition: tcp_session.h:86
static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
Definition: http_curl.cc:216
void delete_session()
Definition: http_client.cc:117
void AssignHeader(const char *ptr, size_t size)
Definition: http_client.cc:316
static void event_cb_impl(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: http_curl.cc:107