|
@@ -8,6 +8,7 @@
|
|
|
|
|
|
|
|
#include "herr.h"
|
|
#include "herr.h"
|
|
|
#include "hlog.h"
|
|
#include "hlog.h"
|
|
|
|
|
+#include "htime.h"
|
|
|
#include "hstring.h"
|
|
#include "hstring.h"
|
|
|
#include "hsocket.h"
|
|
#include "hsocket.h"
|
|
|
#include "hssl.h"
|
|
#include "hssl.h"
|
|
@@ -38,6 +39,7 @@ struct http_client_s {
|
|
|
#endif
|
|
#endif
|
|
|
// for sync
|
|
// for sync
|
|
|
int fd;
|
|
int fd;
|
|
|
|
|
+ unsigned int keepalive_requests;
|
|
|
hssl_t ssl;
|
|
hssl_t ssl;
|
|
|
hssl_ctx_t ssl_ctx;
|
|
hssl_ctx_t ssl_ctx;
|
|
|
bool alloced_ssl_ctx;
|
|
bool alloced_ssl_ctx;
|
|
@@ -57,6 +59,7 @@ struct http_client_s {
|
|
|
curl = NULL;
|
|
curl = NULL;
|
|
|
#endif
|
|
#endif
|
|
|
fd = -1;
|
|
fd = -1;
|
|
|
|
|
+ keepalive_requests = 0;
|
|
|
ssl = NULL;
|
|
ssl = NULL;
|
|
|
ssl_ctx = NULL;
|
|
ssl_ctx = NULL;
|
|
|
alloced_ssl_ctx = false;
|
|
alloced_ssl_ctx = false;
|
|
@@ -249,6 +252,7 @@ int http_client_connect(http_client_t* cli, const char* host, int port, int http
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
cli->fd = connfd;
|
|
cli->fd = connfd;
|
|
|
|
|
+ cli->keepalive_requests = 0;
|
|
|
return connfd;
|
|
return connfd;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -281,20 +285,30 @@ int http_client_recv_data(http_client_t* cli, char* data, int size) {
|
|
|
static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
|
|
static int http_client_exec(http_client_t* cli, HttpRequest* req, HttpResponse* resp) {
|
|
|
// connect -> send -> recv -> http_parser
|
|
// connect -> send -> recv -> http_parser
|
|
|
int err = 0;
|
|
int err = 0;
|
|
|
- int timeout = req->timeout;
|
|
|
|
|
int connfd = cli->fd;
|
|
int connfd = cli->fd;
|
|
|
bool https = req->IsHttps() && !req->IsProxy();
|
|
bool https = req->IsHttps() && !req->IsProxy();
|
|
|
bool keepalive = true;
|
|
bool keepalive = true;
|
|
|
|
|
|
|
|
- time_t start_time = time(NULL);
|
|
|
|
|
- time_t cur_time;
|
|
|
|
|
- int fail_cnt = 0;
|
|
|
|
|
- if (connfd <= 0) {
|
|
|
|
|
-connect:
|
|
|
|
|
- connfd = http_client_connect(cli, req->host.c_str(), req->port, https, MIN(req->connect_timeout, req->timeout));
|
|
|
|
|
- if (connfd < 0) {
|
|
|
|
|
- return connfd;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ time_t connect_timeout = MIN(req->connect_timeout, req->timeout);
|
|
|
|
|
+ time_t timeout_ms = req->timeout * 1000;
|
|
|
|
|
+ time_t start_time = gettick_ms();
|
|
|
|
|
+ time_t cur_time = start_time, left_time = INFINITE;
|
|
|
|
|
+
|
|
|
|
|
+#define CHECK_TIMEOUT \
|
|
|
|
|
+ do { \
|
|
|
|
|
+ if (timeout_ms > 0) { \
|
|
|
|
|
+ cur_time = gettick_ms(); \
|
|
|
|
|
+ if (cur_time - start_time >= timeout_ms) { \
|
|
|
|
|
+ goto timeout; \
|
|
|
|
|
+ } \
|
|
|
|
|
+ left_time = timeout_ms - (cur_time - start_time); \
|
|
|
|
|
+ } \
|
|
|
|
|
+ } while(0);
|
|
|
|
|
+
|
|
|
|
|
+ uint32_t retry_count = req->retry_count;
|
|
|
|
|
+ if (cli->keepalive_requests > 0 && retry_count == 0) {
|
|
|
|
|
+ // maybe keep-alive timeout, retry at least once
|
|
|
|
|
+ retry_count = 1;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (cli->parser == NULL) {
|
|
if (cli->parser == NULL) {
|
|
@@ -304,6 +318,15 @@ connect:
|
|
|
return ERR_NULL_POINTER;
|
|
return ERR_NULL_POINTER;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if (connfd <= 0) {
|
|
|
|
|
+connect:
|
|
|
|
|
+ connfd = http_client_connect(cli, req->host.c_str(), req->port, https, connect_timeout);
|
|
|
|
|
+ if (connfd < 0) {
|
|
|
|
|
+ return connfd;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
cli->parser->SubmitRequest(req);
|
|
cli->parser->SubmitRequest(req);
|
|
|
char recvbuf[1024] = {0};
|
|
char recvbuf[1024] = {0};
|
|
|
int total_nsend, nsend, nrecv;
|
|
int total_nsend, nsend, nrecv;
|
|
@@ -314,21 +337,19 @@ send:
|
|
|
while (cli->parser->GetSendData(&data, &len)) {
|
|
while (cli->parser->GetSendData(&data, &len)) {
|
|
|
total_nsend = 0;
|
|
total_nsend = 0;
|
|
|
while (total_nsend < len) {
|
|
while (total_nsend < len) {
|
|
|
- if (timeout > 0) {
|
|
|
|
|
- cur_time = time(NULL);
|
|
|
|
|
- if (cur_time - start_time >= timeout) {
|
|
|
|
|
- return ERR_TASK_TIMEOUT;
|
|
|
|
|
- }
|
|
|
|
|
- so_sndtimeo(cli->fd, (timeout-(cur_time-start_time)) * 1000);
|
|
|
|
|
|
|
+ CHECK_TIMEOUT
|
|
|
|
|
+ if (left_time != INFINITE) {
|
|
|
|
|
+ so_sndtimeo(cli->fd, left_time);
|
|
|
}
|
|
}
|
|
|
nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
|
|
nsend = http_client_send_data(cli, data + total_nsend, len - total_nsend);
|
|
|
if (nsend <= 0) {
|
|
if (nsend <= 0) {
|
|
|
|
|
+ CHECK_TIMEOUT
|
|
|
err = socket_errno();
|
|
err = socket_errno();
|
|
|
if (err == EINTR) continue;
|
|
if (err == EINTR) continue;
|
|
|
- if (++fail_cnt == 1) {
|
|
|
|
|
- // maybe keep-alive timeout, try again
|
|
|
|
|
|
|
+ if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
|
|
|
cli->Close();
|
|
cli->Close();
|
|
|
err = 0;
|
|
err = 0;
|
|
|
|
|
+ if (req->retry_delay > 0) hv_msleep(req->retry_delay);
|
|
|
goto connect;
|
|
goto connect;
|
|
|
}
|
|
}
|
|
|
goto disconnect;
|
|
goto disconnect;
|
|
@@ -340,25 +361,23 @@ send:
|
|
|
cli->parser->InitResponse(resp);
|
|
cli->parser->InitResponse(resp);
|
|
|
recv:
|
|
recv:
|
|
|
do {
|
|
do {
|
|
|
- if (timeout > 0) {
|
|
|
|
|
- cur_time = time(NULL);
|
|
|
|
|
- if (cur_time - start_time >= timeout) {
|
|
|
|
|
- return ERR_TASK_TIMEOUT;
|
|
|
|
|
- }
|
|
|
|
|
- so_rcvtimeo(cli->fd, (timeout-(cur_time-start_time)) * 1000);
|
|
|
|
|
|
|
+ CHECK_TIMEOUT
|
|
|
|
|
+ if (left_time != INFINITE) {
|
|
|
|
|
+ so_rcvtimeo(cli->fd, left_time);
|
|
|
}
|
|
}
|
|
|
nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
|
|
nrecv = http_client_recv_data(cli, recvbuf, sizeof(recvbuf));
|
|
|
if (nrecv <= 0) {
|
|
if (nrecv <= 0) {
|
|
|
|
|
+ CHECK_TIMEOUT
|
|
|
err = socket_errno();
|
|
err = socket_errno();
|
|
|
if (err == EINTR) continue;
|
|
if (err == EINTR) continue;
|
|
|
if (cli->parser->IsEof()) {
|
|
if (cli->parser->IsEof()) {
|
|
|
err = 0;
|
|
err = 0;
|
|
|
goto disconnect;
|
|
goto disconnect;
|
|
|
}
|
|
}
|
|
|
- if (++fail_cnt == 1) {
|
|
|
|
|
- // maybe keep-alive timeout, try again
|
|
|
|
|
|
|
+ if (retry_count-- > 0 && left_time > req->retry_delay + connect_timeout * 1000) {
|
|
|
cli->Close();
|
|
cli->Close();
|
|
|
err = 0;
|
|
err = 0;
|
|
|
|
|
+ if (req->retry_delay > 0) hv_msleep(req->retry_delay);
|
|
|
goto connect;
|
|
goto connect;
|
|
|
}
|
|
}
|
|
|
goto disconnect;
|
|
goto disconnect;
|
|
@@ -370,10 +389,14 @@ recv:
|
|
|
} while(!cli->parser->IsComplete());
|
|
} while(!cli->parser->IsComplete());
|
|
|
|
|
|
|
|
keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
|
|
keepalive = req->IsKeepAlive() && resp->IsKeepAlive();
|
|
|
- if (!keepalive) {
|
|
|
|
|
|
|
+ if (keepalive) {
|
|
|
|
|
+ ++cli->keepalive_requests;
|
|
|
|
|
+ } else {
|
|
|
cli->Close();
|
|
cli->Close();
|
|
|
}
|
|
}
|
|
|
return 0;
|
|
return 0;
|
|
|
|
|
+timeout:
|
|
|
|
|
+ err = ERR_TASK_TIMEOUT;
|
|
|
disconnect:
|
|
disconnect:
|
|
|
cli->Close();
|
|
cli->Close();
|
|
|
return err;
|
|
return err;
|