24 #include <curl/curl.h>
25 #include <boost/asio.hpp>
26 #include <boost/bind/bind.hpp>
27 #include <boost/intrusive_ptr.hpp>
29 using namespace boost::placeholders;
31 #define MSG_OUT stdout
55 if ( CURLM_OK != code )
60 case CURLM_CALL_MULTI_PERFORM: s=
"CURLM_CALL_MULTI_PERFORM";
break;
61 case CURLM_BAD_HANDLE: s=
"CURLM_BAD_HANDLE";
break;
62 case CURLM_BAD_EASY_HANDLE: s=
"CURLM_BAD_EASY_HANDLE";
break;
63 case CURLM_OUT_OF_MEMORY: s=
"CURLM_OUT_OF_MEMORY";
break;
64 case CURLM_INTERNAL_ERROR: s=
"CURLM_INTERNAL_ERROR";
break;
65 case CURLM_UNKNOWN_OPTION: s=
"CURLM_UNKNOWN_OPTION";
break;
66 case CURLM_LAST: s=
"CURLM_LAST";
break;
67 case CURLM_BAD_SOCKET: s=
"CURLM_BAD_SOCKET";
break;
68 default: s=
"CURLM_unknown";
break;
71 fprintf(
MSG_OUT,
"\nERROR: %s returns %s", where, s);
85 while ((msg = curl_multi_info_read(g->
multi, &msgs_left)))
87 if (msg->msg == CURLMSG_DONE)
89 easy = msg->easy_handle;
90 res = msg->data.result;
91 curl_easy_getinfo(easy, CURLINFO_PRIVATE, &conn);
92 curl_easy_getinfo(easy, CURLINFO_EFFECTIVE_URL, &eff_url);
96 std::string empty_str(
"");
107 const boost::system::error_code &error,
108 std::size_t bytes_transferred)
111 if (session->IsClosed())
return;
116 rc = curl_multi_socket_action(g->
multi, session->socket()->native_handle(), action, &g->
still_running);
129 const boost::system::error_code &error, std::size_t bytes_transferred)
131 std::scoped_lock lock(session->mutex());
134 if (!session->Connection())
return;
136 HttpClient *client = session->Connection()->client();
139 LOG(ERROR,
"HttpClient:unable to call ProcessEvent() as HttpClient is NULL" <<
140 ", session :" << session <<
141 ", session->Connection(): " << session->Connection() <<
142 ", HttpClient :" << session->Connection()->client());
183 if (!session || session->
IsClosed())
186 boost::asio::ip::tcp::socket * tcp_socket = session->
socket();
190 if ( act == CURL_POLL_IN )
192 tcp_socket->async_read_some(boost::asio::null_buffers(),
196 else if ( act == CURL_POLL_OUT )
198 tcp_socket->async_write_some(boost::asio::null_buffers(),
202 else if ( act == CURL_POLL_INOUT )
204 tcp_socket->async_read_some(boost::asio::null_buffers(),
207 tcp_socket->async_write_some(boost::asio::null_buffers(),
219 curl_easy_getinfo(easy, CURLINFO_PRIVATE, &sock_info->
conn_info);
221 if (!
setsock(sock_info, s, easy, action, g)) {
226 curl_multi_assign(g->
multi, s, sock_info);
230 static int sock_cb(CURL *e, curl_socket_t s,
int what,
void *cbp,
void *sockp)
235 if ( what == CURL_POLL_REMOVE )
247 setsock(sock_info, s, e, what, g);
255 static size_t write_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
257 size_t written = size * nmemb;
265 static size_t header_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
267 size_t written = size * nmemb;
274 static size_t read_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
278 char *str = curl_handle->
post;
280 size_t maxb = size*nmemb;
284 datasize = curl_handle->
post_len - offset;
286 if (maxb >= datasize) {
287 memcpy(ptr, str + offset, datasize);
291 memcpy(ptr, str + offset, maxb);
301 static int prog_cb (
void *p,
double dltotal,
double dlnow,
double ult,
312 curlsocktype purpose,
313 struct curl_sockaddr *address)
317 curl_socket_t sockfd = CURL_SOCKET_BAD;
320 if (purpose == CURLSOCKTYPE_IPCXN && address->family == AF_INET)
324 sockfd = session->
socket()->native_handle();
342 CURLMcode m_rc = curl_multi_add_handle(g->
multi, conn->
easy);
343 if (m_rc != CURLM_OK)
348 CURLMcode rc = curl_multi_perform(g->
multi, &counter);
349 if (rc == CURLM_OK && counter <= 0) {
352 const boost::system::error_code ec;
379 curl_easy_setopt(curl_handle->
easy, CURLOPT_PRIVATE, NULL);
380 curl_multi_remove_handle(g->
multi, curl_handle->
easy);
381 curl_slist_free_all(curl_handle->
headers);
382 free(curl_handle->
post);
383 free(curl_handle->
url);
384 curl_easy_cleanup(curl_handle->
easy);
391 bool header,
bool short_timeout,
bool reuse)
395 conn->
error[CURL_ERROR_SIZE]=
'\0';
397 conn->
easy = curl_easy_init();
404 curl_easy_setopt(conn->
easy, CURLOPT_FOLLOWLOCATION, 1L);
405 curl_easy_setopt(conn->
easy, CURLOPT_WRITEFUNCTION,
write_cb);
407 curl_easy_setopt(conn->
easy, CURLOPT_HEADERFUNCTION,
header_cb);
409 curl_easy_setopt(conn->
easy, CURLOPT_READFUNCTION,
read_cb);
411 curl_easy_setopt(conn->
easy, CURLOPT_ERRORBUFFER, conn->
error);
412 curl_easy_setopt(conn->
easy, CURLOPT_PRIVATE, conn);
413 curl_easy_setopt(conn->
easy, CURLOPT_NOPROGRESS, 1L);
414 curl_easy_setopt(conn->
easy, CURLOPT_PROGRESSFUNCTION,
prog_cb);
415 curl_easy_setopt(conn->
easy, CURLOPT_PROGRESSDATA, conn);
416 curl_easy_setopt(conn->
easy, CURLOPT_CONNECTTIMEOUT, 4L);
419 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_TIME, 3L);
420 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
423 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_TIME, 30L);
424 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
426 curl_easy_setopt(conn->
easy, CURLOPT_FORBID_REUSE, 1L);
434 curl_easy_setopt(conn->
easy, CURLOPT_CLOSESOCKETDATA,
connection);
441 curl_easy_setopt(conn->
easy, CURLOPT_URL, conn->
url);
446 curl_easy_setopt(conn->
easy, CURLOPT_HTTPHEADER, conn->
headers);
450 const char *client_cert_type,
const char *client_key,
451 const char *ca_cert) {
452 curl_easy_setopt(conn->
easy, CURLOPT_SSLCERT, client_cert);
453 curl_easy_setopt(conn->
easy, CURLOPT_SSLCERTTYPE, client_cert_type);
454 curl_easy_setopt(conn->
easy, CURLOPT_SSLKEY, client_key);
455 curl_easy_setopt(conn->
easy, CURLOPT_CAINFO, ca_cert);
456 if (ca_cert[0] ==
'\0') {
458 curl_easy_setopt(conn->
easy, CURLOPT_SSL_VERIFYPEER, 0L);
459 curl_easy_setopt(conn->
easy, CURLOPT_SSL_VERIFYHOST, 0L);
464 conn->
post = (
char *) malloc(len);
467 curl_easy_setopt(conn->
easy, CURLOPT_POST, 1);
468 curl_easy_setopt(conn->
easy, CURLOPT_POSTFIELDS, conn->
post);
469 curl_easy_setopt(conn->
easy, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
473 conn->
post = (
char *) malloc(len);
474 memcpy(conn->
post, put, len);
476 curl_easy_setopt(conn->
easy, CURLOPT_UPLOAD, 1);
477 curl_easy_setopt(conn->
easy, CURLOPT_PUT, 1);
478 curl_easy_setopt(conn->
easy, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
482 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
487 curl_easy_setopt(conn->
easy, CURLOPT_CUSTOMREQUEST,
"HEAD");
488 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
501 curl_easy_setopt(conn->
easy, CURLOPT_CUSTOMREQUEST,
"DELETE");
502 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
511 g->
multi = curl_multi_init();
514 curl_multi_setopt(g->
multi, CURLMOPT_SOCKETFUNCTION,
sock_cb);
515 curl_multi_setopt(g->
multi, CURLMOPT_SOCKETDATA, g);
517 curl_multi_setopt(g->
multi, CURLMOPT_TIMERDATA,
client);
void SetConnection(HttpConnection *conn)
struct _GlobalInfo * GlobalInfo()
void ProcessEvent(EnqueuedCb cb)
static const uint32_t kDefaultTimeout
bool IsErrorHard(const boost::system::error_code &ec)
HttpClientSession * CreateSession()
HttpClientSession * session()
void AssignData(const char *ptr, size_t size)
struct _ConnInfo * curl_handle()
void set_session(HttpClientSession *session)
void UpdateOffset(size_t bytes)
void AssignHeader(const char *ptr, size_t size)
void set_curl_handle(struct _ConnInfo *handle)
virtual Socket * socket() const
int http_post(ConnInfo *conn, GlobalInfo *g)
void set_header_options(ConnInfo *conn, const char *options)
static void remsock(SockInfo *sock_info, GlobalInfo *g)
void set_post_string(ConnInfo *conn, const char *post, uint32_t len)
void del_conn(HttpConnection *connection, GlobalInfo *g)
int http_delete(ConnInfo *conn, GlobalInfo *g)
boost::intrusive_ptr< HttpClientSession > TcpSessionPtr
int http_head(ConnInfo *conn, GlobalInfo *g)
static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
void set_url(ConnInfo *conn, const char *url)
void set_ssl_options(ConnInfo *conn, const char *client_cert, const char *client_cert_type, const char *client_key, const char *ca_cert)
void set_put_string(ConnInfo *conn, const char *put, uint32_t len)
static curl_socket_t open_socket(void *data, curlsocktype purpose, struct curl_sockaddr *address)
static void event_cb(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)
void del_curl_handle(ConnInfo *curl_handle, GlobalInfo *g)
static void event_cb_impl(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)
int http_put(ConnInfo *conn, GlobalInfo *g)
static bool setsock(SockInfo *sock_info, curl_socket_t s, CURL *e, int act, GlobalInfo *g)
ConnInfo * new_conn(HttpConnection *connection, GlobalInfo *g, bool header, bool short_timeout, bool reuse)
static void check_multi_info(GlobalInfo *g)
const CurlErrorCategory curl_error_category
static int multi_timer_cb(CURLM *multi, long timeout_ms, HttpClient *client)
bool timer_cb(GlobalInfo *g)
static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data)
int http_get(ConnInfo *conn, GlobalInfo *g)
static size_t read_cb(void *ptr, size_t size, size_t nmemb, void *data)
static void mcode_or_die(const char *where, CURLMcode code)
static int prog_cb(void *p, double dltotal, double dlnow, double ult, double uln)
static int send_perform(ConnInfo *conn, GlobalInfo *g)
static int close_socket(void *clientp, curl_socket_t item)
static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
int curl_init(HttpClient *client)
static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
#define LOG(_Level, _Msg)
char error[CURL_ERROR_SIZE+1]
struct curl_slist * headers
HttpConnection * connection