Add http post feature for HttpClient (#773)

This commit is contained in:
Yunfeng,Wu
2019-03-19 22:05:33 +08:00
committed by ZHAO Chun
parent 1f092bb9fb
commit fb4e77d6d6
4 changed files with 83 additions and 2 deletions

2
.gitignore vendored
View File

@ -8,3 +8,5 @@ gensrc/build
fe/target
thirdparty/src
*.so.tmp
.DS_Store
*.iml

View File

@ -27,6 +27,10 @@ HttpClient::~HttpClient() {
curl_easy_cleanup(_curl);
_curl = nullptr;
}
if(_header_list != nullptr) {
curl_slist_free_all(_header_list);
_header_list = nullptr;
}
}
Status HttpClient::init(const std::string& url) {
@ -39,6 +43,10 @@ Status HttpClient::init(const std::string& url) {
curl_easy_reset(_curl);
}
if(_header_list != nullptr) {
curl_slist_free_all(_header_list);
_header_list = nullptr;
}
// set error_buf
_error_buf[0] = 0;
auto code = curl_easy_setopt(_curl, CURLOPT_ERRORBUFFER, _error_buf);
@ -131,6 +139,18 @@ size_t HttpClient::on_response_data(const void* data, size_t length) {
return length;
}
// Status HttpClient::execute_post_request(const std::string& post_data, const std::function<bool(const void* data, size_t length)>& callback = {}) {
// _callback = &callback;
// set_post_body(post_data);
// return execute(callback);
// }
Status HttpClient::execute_post_request(const std::string& post_data, std::string* response) {
set_method(POST);
set_post_body(post_data);
return execute(response);
}
Status HttpClient::execute(const std::function<bool(const void* data, size_t length)>& callback) {
_callback = &callback;
auto code = curl_easy_perform(_curl);

View File

@ -26,7 +26,7 @@
#include "http/http_headers.h"
#include "http/http_method.h"
#include "http/utils.h"
#include "http/http_response.h"
namespace doris {
// Helper class to access HTTP resource
@ -54,6 +54,19 @@ public:
curl_easy_setopt(_curl, CURLOPT_PASSWORD, passwd.c_str());
}
// content_type such as "application/json"
void set_content_type(const std::string content_type) {
std::string scratch_str = "Content-Type: " + content_type;
_header_list = curl_slist_append(_header_list, scratch_str.c_str());
curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _header_list);
}
// you must set CURLOPT_POSTFIELDSIZE before CURLOPT_COPYPOSTFIELDS options, otherwise will cause request hanging up
void set_post_body(const std::string& post_body) {
curl_easy_setopt(_curl, CURLOPT_POSTFIELDSIZE, (long)post_body.length());
curl_easy_setopt(_curl, CURLOPT_COPYPOSTFIELDS, post_body.c_str());
}
// TODO(zc): support set header
// void set_header(const std::string& key, const std::string& value) {
// _cntl.http_request().SetHeader(key, value);
@ -85,6 +98,12 @@ public:
return cl;
}
long get_http_status() const {
long code;
curl_easy_getinfo(_curl, CURLINFO_RESPONSE_CODE, &code);
return code;
}
// execute a head method
Status head() {
set_method(HEAD);
@ -95,6 +114,8 @@ public:
// a file to local_path
Status download(const std::string& local_path);
Status execute_post_request(const std::string& post_data, std::string* response);
// execute a simple method, and its response is saved in response argument
Status execute(std::string* response);
@ -111,6 +132,7 @@ private:
using HttpCallback = std::function<bool(const void* data, size_t length)>;
const HttpCallback* _callback = nullptr;
char _error_buf[CURL_ERROR_SIZE];
curl_slist *_header_list = nullptr;
};
}

View File

@ -47,7 +47,28 @@ public:
}
};
class HttpClientTestSimplePostHandler : public HttpHandler {
public:
void handle(HttpRequest* req) override {
std::string user;
std::string passwd;
if (!parse_basic_auth(*req, &user, &passwd) || user != "test1") {
HttpChannel::send_basic_challenge(req, "abc");
return;
}
if (req->method() == HttpMethod::POST) {
std::string post_body = req->get_request_body();
if (!post_body.empty()) {
HttpChannel::send_reply(req, post_body);
} else {
HttpChannel::send_reply(req, "empty");
}
}
}
};
static HttpClientTestSimpleGetHandler s_simple_get_handler = HttpClientTestSimpleGetHandler();
static HttpClientTestSimplePostHandler s_simple_post_handler = HttpClientTestSimplePostHandler();
static EvHttpServer* s_server = nullptr;
class HttpClientTest : public testing::Test {
@ -59,6 +80,7 @@ public:
s_server = new EvHttpServer(29386);
s_server->register_handler(GET, "/simple_get", &s_simple_get_handler);
s_server->register_handler(HEAD, "/simple_get", &s_simple_get_handler);
s_server->register_handler(POST, "/simple_post", &s_simple_post_handler);
s_server->start();
}
@ -109,9 +131,24 @@ TEST_F(HttpClientTest, get_failed) {
auto st = client.init("http://127.0.0.1:29386/simple_get");
ASSERT_TRUE(st.ok());
client.set_method(GET);
client.set_basic_auth("test1", "");
std::string response;
st = client.execute(&response);
ASSERT_FALSE(st.ok());
ASSERT_FALSE(!st.ok());
}
TEST_F(HttpClientTest, post_normal) {
HttpClient client;
auto st = client.init("http://127.0.0.1:29386/simple_post");
ASSERT_TRUE(st.ok());
client.set_method(POST);
client.set_basic_auth("test1", "");
std::string response;
std::string request_body = "simple post body query";
st = client.execute_post_request(request_body, &response);
ASSERT_TRUE(st.ok());
ASSERT_EQ(response.length(), request_body.length());
ASSERT_STREQ(response.c_str(), request_body.c_str());
}
}