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>
30 #define MSG_OUT stdout
56 if ( CURLM_OK != code )
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;
72 fprintf(
MSG_OUT,
"\nERROR: %s returns %s", where, s);
86 while ((msg = curl_multi_info_read(g->
multi, &msgs_left)))
88 if (msg->msg == CURLMSG_DONE)
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);
96 boost::system::error_code error(res, curl_error_category);
97 std::string empty_str(
"");
108 const boost::system::error_code &error,
109 std::size_t bytes_transferred)
112 if (session->IsClosed())
return;
117 rc = curl_multi_socket_action(g->
multi, session->socket()->native_handle(), action, &g->
still_running);
130 const boost::system::error_code &error, std::size_t bytes_transferred)
132 tbb::mutex::scoped_lock lock(session->mutex());
135 if (!session->Connection())
return;
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());
184 if (!session || session->
IsClosed())
187 boost::asio::ip::tcp::socket * tcp_socket = session->
socket();
191 if ( act == CURL_POLL_IN )
193 tcp_socket->async_read_some(boost::asio::null_buffers(),
197 else if ( act == CURL_POLL_OUT )
199 tcp_socket->async_write_some(boost::asio::null_buffers(),
203 else if ( act == CURL_POLL_INOUT )
205 tcp_socket->async_read_some(boost::asio::null_buffers(),
208 tcp_socket->async_write_some(boost::asio::null_buffers(),
220 curl_easy_getinfo(easy, CURLINFO_PRIVATE, &sock_info->
conn_info);
222 if (!
setsock(sock_info, s, easy, action, g)) {
227 curl_multi_assign(g->
multi, s, sock_info);
231 static int sock_cb(CURL *e, curl_socket_t s,
int what,
void *cbp,
void *sockp)
236 if ( what == CURL_POLL_REMOVE )
248 setsock(sock_info, s, e, what, g);
256 static size_t write_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
258 size_t written = size * nmemb;
266 static size_t header_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
268 size_t written = size * nmemb;
275 static size_t read_cb(
void *ptr,
size_t size,
size_t nmemb,
void *data)
279 char *str = curl_handle->
post;
281 size_t maxb = size*nmemb;
285 datasize = curl_handle->
post_len - offset;
287 if (maxb >= datasize) {
288 memcpy(ptr, str + offset, datasize);
292 memcpy(ptr, str + offset, maxb);
302 static int prog_cb (
void *p,
double dltotal,
double dlnow,
double ult,
313 curlsocktype purpose,
314 struct curl_sockaddr *address)
318 curl_socket_t sockfd = CURL_SOCKET_BAD;
321 if (purpose == CURLSOCKTYPE_IPCXN && address->family == AF_INET)
325 sockfd = session->
socket()->native_handle();
343 CURLMcode m_rc = curl_multi_add_handle(g->
multi, conn->
easy);
344 if (m_rc != CURLM_OK)
349 CURLMcode rc = curl_multi_perform(g->
multi, &counter);
350 if (rc == CURLM_OK && counter <= 0) {
353 const boost::system::error_code ec;
367 tbb::mutex::scoped_lock lock(connection->
session()->
mutex());
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);
392 bool header,
bool short_timeout,
bool reuse)
396 conn->
error[CURL_ERROR_SIZE]=
'\0';
398 conn->
easy = curl_easy_init();
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);
420 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_TIME, 3L);
421 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
424 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_TIME, 30L);
425 curl_easy_setopt(conn->
easy, CURLOPT_LOW_SPEED_LIMIT, 10L);
427 curl_easy_setopt(conn->
easy, CURLOPT_FORBID_REUSE, 1L);
431 curl_easy_setopt(conn->
easy, CURLOPT_OPENSOCKETDATA, connection);
435 curl_easy_setopt(conn->
easy, CURLOPT_CLOSESOCKETDATA, connection);
441 conn->
url = strdup(url);
442 curl_easy_setopt(conn->
easy, CURLOPT_URL, conn->
url);
447 curl_easy_setopt(conn->
easy, CURLOPT_HTTPHEADER, conn->
headers);
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') {
459 curl_easy_setopt(conn->
easy, CURLOPT_SSL_VERIFYPEER, 0L);
460 curl_easy_setopt(conn->
easy, CURLOPT_SSL_VERIFYHOST, 0L);
465 conn->
post = (
char *) malloc(len);
466 memcpy(conn->
post, post, 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);
474 conn->
post = (
char *) malloc(len);
475 memcpy(conn->
post, put, 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);
483 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
488 curl_easy_setopt(conn->
easy, CURLOPT_CUSTOMREQUEST,
"HEAD");
489 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
502 curl_easy_setopt(conn->
easy, CURLOPT_CUSTOMREQUEST,
"DELETE");
503 CURLMcode rc = curl_multi_add_handle(g->
multi, conn->
easy);
512 g->
multi = curl_multi_init();
515 curl_multi_setopt(g->
multi, CURLMOPT_SOCKETFUNCTION,
sock_cb);
516 curl_multi_setopt(g->
multi, CURLMOPT_SOCKETDATA, g);
518 curl_multi_setopt(g->
multi, CURLMOPT_TIMERDATA, client);
static int prog_cb(void *p, double dltotal, double dlnow, double ult, double uln)
static void remsock(SockInfo *sock_info, GlobalInfo *g)
void UpdateOffset(size_t bytes)
static void check_multi_info(GlobalInfo *g)
static int send_perform(ConnInfo *conn, GlobalInfo *g)
static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *data)
int http_head(ConnInfo *conn, GlobalInfo *g)
static curl_socket_t open_socket(void *data, curlsocktype purpose, struct curl_sockaddr *address)
struct _GlobalInfo * GlobalInfo()
struct curl_slist * headers
void ProcessEvent(EnqueuedCb cb)
int http_delete(ConnInfo *conn, GlobalInfo *g)
boost::intrusive_ptr< HttpClientSession > TcpSessionPtr
static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp)
HttpClientSession * session()
HttpClientSession * CreateSession()
static size_t read_cb(void *ptr, size_t size, size_t nmemb, void *data)
int curl_init(HttpClient *client)
HttpConnection * connection
void set_put_string(ConnInfo *conn, const char *put, uint32_t len)
static bool setsock(SockInfo *sock_info, curl_socket_t s, CURL *e, int act, GlobalInfo *g)
int http_put(ConnInfo *conn, GlobalInfo *g)
static void mcode_or_die(const char *where, CURLMcode code)
void set_post_string(ConnInfo *conn, const char *post, uint32_t len)
static const uint32_t kDefaultTimeout
char error[CURL_ERROR_SIZE+1]
void AssignData(const char *ptr, size_t size)
int http_get(ConnInfo *conn, GlobalInfo *g)
void del_curl_handle(ConnInfo *curl_handle, GlobalInfo *g)
void del_conn(HttpConnection *connection, GlobalInfo *g)
struct _ConnInfo * curl_handle()
static int close_socket(void *clientp, curl_socket_t item)
int http_post(ConnInfo *conn, GlobalInfo *g)
static size_t header_cb(void *ptr, size_t size, size_t nmemb, void *data)
bool IsErrorHard(const boost::system::error_code &ec)
void set_header_options(ConnInfo *conn, const char *options)
void SetConnection(HttpConnection *conn)
void set_url(ConnInfo *conn, const char *url)
#define LOG(_Level, _Msg)
void set_curl_handle(struct _ConnInfo *handle)
void set_ssl_options(ConnInfo *conn, const char *client_cert, const char *client_cert_type, const char *client_key, const char *ca_cert)
bool timer_cb(GlobalInfo *g)
const CurlErrorCategory curl_error_category
ConnInfo * new_conn(HttpConnection *connection, GlobalInfo *g, bool header, bool short_timeout, bool reuse)
static int multi_timer_cb(CURLM *multi, long timeout_ms, HttpClient *client)
void set_session(HttpClientSession *session)
static void event_cb(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)
virtual Socket * socket() const
static void addsock(curl_socket_t s, CURL *easy, int action, GlobalInfo *g)
void AssignHeader(const char *ptr, size_t size)
static void event_cb_impl(GlobalInfo *g, TcpSessionPtr session, int action, const boost::system::error_code &error, std::size_t bytes_transferred)