Refine the REST examples; refine the http message parsing.
This commit is contained in:
@@ -6,5 +6,5 @@ file(GLOB SRCS *.cc *.h)
|
|||||||
|
|
||||||
add_executable(rest_book_client ${SRCS})
|
add_executable(rest_book_client ${SRCS})
|
||||||
|
|
||||||
target_link_libraries(rest_book_client webcc ${Boost_LIBRARIES})
|
target_link_libraries(rest_book_client webcc jsoncpp ${Boost_LIBRARIES})
|
||||||
target_link_libraries(rest_book_client "${CMAKE_THREAD_LIBS_INIT}")
|
target_link_libraries(rest_book_client "${CMAKE_THREAD_LIBS_INIT}")
|
||||||
|
|||||||
@@ -1,87 +1,209 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "boost/algorithm/string.hpp"
|
||||||
|
#include "json/json.h" // jsoncpp
|
||||||
|
|
||||||
#include "webcc/http_client.h"
|
#include "webcc/http_client.h"
|
||||||
#include "webcc/http_request.h"
|
#include "webcc/http_request.h"
|
||||||
#include "webcc/http_response.h"
|
#include "webcc/http_response.h"
|
||||||
|
|
||||||
class BookListClient {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class BookClientBase {
|
||||||
public:
|
public:
|
||||||
BookListClient() {
|
BookClientBase(const std::string& host, const std::string& port)
|
||||||
host_ = "localhost";
|
: host_(host), port_(port) {
|
||||||
port_ = "8080";
|
}
|
||||||
|
|
||||||
|
bool Request(const std::string& method,
|
||||||
|
const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
webcc::HttpResponse* http_response) {
|
||||||
|
webcc::HttpRequest http_request;
|
||||||
|
|
||||||
|
http_request.set_method(method);
|
||||||
|
http_request.set_url(url);
|
||||||
|
http_request.SetHost(host_, port_);
|
||||||
|
if (!content.empty()) { // TODO
|
||||||
|
http_request.SetContent(content);
|
||||||
|
}
|
||||||
|
http_request.Build();
|
||||||
|
|
||||||
|
webcc::HttpClient http_client;
|
||||||
|
webcc::Error error = http_client.SendRequest(http_request, http_response);
|
||||||
|
|
||||||
|
return error == webcc::kNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string host_;
|
||||||
|
std::string port_;
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class BookListClient : public BookClientBase {
|
||||||
|
public:
|
||||||
|
BookListClient(const std::string& host, const std::string& port)
|
||||||
|
: BookClientBase(host, port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ListBooks() {
|
bool ListBooks() {
|
||||||
webcc::HttpRequest http_request;
|
|
||||||
|
|
||||||
http_request.set_method(webcc::kHttpGet);
|
|
||||||
http_request.set_url("/books");
|
|
||||||
http_request.SetHost(host_, port_);
|
|
||||||
|
|
||||||
http_request.Build();
|
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
|
if (!Request(webcc::kHttpGet, "/books", "", &http_response)) {
|
||||||
webcc::HttpClient http_client;
|
|
||||||
webcc::Error error = http_client.SendRequest(http_request, &http_response);
|
|
||||||
|
|
||||||
if (error != webcc::kNoError) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Book list: " << std::endl
|
std::cout << http_response.content() << std::endl;
|
||||||
<< http_response.content() << std::endl;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
bool CreateBook(const std::string& id,
|
||||||
std::string host_;
|
const std::string& title,
|
||||||
std::string port_;
|
double price) {
|
||||||
|
Json::Value root(Json::objectValue);
|
||||||
|
root["id"] = id;
|
||||||
|
root["title"] = title;
|
||||||
|
root["price"] = price;
|
||||||
|
|
||||||
|
Json::StreamWriterBuilder builder;
|
||||||
|
std::string book_json = Json::writeString(builder, root);
|
||||||
|
|
||||||
|
webcc::HttpResponse http_response;
|
||||||
|
if (!Request(webcc::kHttpPost, "/books", book_json, &http_response)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << http_response.status() << std::endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BookDetailClient {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
class BookDetailClient : public BookClientBase {
|
||||||
public:
|
public:
|
||||||
BookDetailClient() {
|
BookDetailClient(const std::string& host, const std::string& port)
|
||||||
host_ = "localhost";
|
: BookClientBase(host, port) {
|
||||||
port_ = "8080";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GetBook(const std::string& id) {
|
bool GetBook(const std::string& id) {
|
||||||
webcc::HttpRequest http_request;
|
|
||||||
|
|
||||||
http_request.set_method(webcc::kHttpGet);
|
|
||||||
http_request.set_url("/books/" + id);
|
|
||||||
http_request.SetHost(host_, port_);
|
|
||||||
|
|
||||||
http_request.Build();
|
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
|
if (!Request(webcc::kHttpGet, "/books/" + id, "", &http_response)) {
|
||||||
webcc::HttpClient http_client;
|
|
||||||
webcc::Error error = http_client.SendRequest(http_request, &http_response);
|
|
||||||
|
|
||||||
if (error != webcc::kNoError) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Book: " << id << std::endl
|
std::cout << http_response.content() << std::endl;
|
||||||
<< http_response.content() << std::endl;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
std::string host_;
|
|
||||||
std::string port_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int main() {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
BookListClient book_list_client;
|
|
||||||
book_list_client.ListBooks();
|
|
||||||
|
|
||||||
BookDetailClient book_detail_client;
|
std::string g_host;
|
||||||
book_detail_client.GetBook("1");
|
std::string g_port;
|
||||||
|
|
||||||
|
void ListBooks() {
|
||||||
|
std::cout << "List books" << std::endl;
|
||||||
|
|
||||||
|
BookListClient client(g_host, g_port);
|
||||||
|
|
||||||
|
client.ListBooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateBook(const std::string& id,
|
||||||
|
const std::string& title,
|
||||||
|
double price) {
|
||||||
|
std::cout << "Create book: " << id << " " << title << " " << price << std::endl;
|
||||||
|
|
||||||
|
BookListClient client(g_host, g_port);
|
||||||
|
|
||||||
|
client.CreateBook(id, title, price);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Help(const char* argv0) {
|
||||||
|
std::cout << "Usage: " << argv0 << " <host> <port>" << std::endl;
|
||||||
|
std::cout << " E.g.," << std::endl;
|
||||||
|
std::cout << " " << argv0 << " localhost 8080" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetUserInput() {
|
||||||
|
char input[256];
|
||||||
|
std::size_t length = 0;
|
||||||
|
do {
|
||||||
|
std::cout << ">> ";
|
||||||
|
std::cin.getline(input, 256);
|
||||||
|
length = strlen(input);
|
||||||
|
} while (length == 0);
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (argc != 3) {
|
||||||
|
Help(argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_host = argv[1];
|
||||||
|
g_port = argv[2];
|
||||||
|
|
||||||
|
// Type commands to execute actions.
|
||||||
|
// Commands: list, create, update, remove
|
||||||
|
// Examples:
|
||||||
|
// >> list
|
||||||
|
// >> create 1 { "title": "1984", "price": 12.3 }
|
||||||
|
// >> detail 1
|
||||||
|
// >> update 1 { "price": 32 }
|
||||||
|
// >> delete 1
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
std::string input = GetUserInput();
|
||||||
|
boost::trim(input);
|
||||||
|
|
||||||
|
std::string command;
|
||||||
|
std::size_t i = input.find(' ');
|
||||||
|
if (i == std::string::npos) {
|
||||||
|
command = input;
|
||||||
|
} else {
|
||||||
|
command = input.substr(0, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == "exit") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == "list") {
|
||||||
|
ListBooks();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++i;
|
||||||
|
|
||||||
|
std::size_t j = input.find(' ', i);
|
||||||
|
std::string id = input.substr(i, j - i);
|
||||||
|
i = j + 1;
|
||||||
|
|
||||||
|
if (command == "create") {
|
||||||
|
std::string json = input.substr(i);
|
||||||
|
std::cout << "json:" << json << std::endl;
|
||||||
|
|
||||||
|
Json::Value root;
|
||||||
|
Json::CharReaderBuilder builder;
|
||||||
|
std::string errs;
|
||||||
|
if (Json::parseFromStream(builder, std::stringstream(json), &root, &errs)) {
|
||||||
|
CreateBook(id, root["title"].asString(), root["price"].asDouble());
|
||||||
|
} else {
|
||||||
|
std::cerr << errs << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//BookDetailClient book_detail_client(host, port);
|
||||||
|
//book_detail_client.GetBook("1");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "book_services.h"
|
#include "book_services.h"
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <iostream>
|
||||||
#include "boost/lexical_cast.hpp"
|
#include "boost/lexical_cast.hpp"
|
||||||
#include "json/json.h" // jsoncpp
|
#include "json/json.h" // jsoncpp
|
||||||
|
|
||||||
@@ -28,16 +29,16 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os, const Book& book) {
|
||||||
|
os << "{ " << book.id << ", " << book.title << ", " << book.price << " }";
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
|
||||||
static const Book kNullBook{};
|
static const Book kNullBook{};
|
||||||
|
|
||||||
class BookStore {
|
class BookStore {
|
||||||
public:
|
public:
|
||||||
BookStore() {
|
BookStore() = default;
|
||||||
// Prepare test data.
|
|
||||||
books_.push_back({ "1", "Title1", 11.1 });
|
|
||||||
books_.push_back({ "2", "Title2", 22.2 });
|
|
||||||
books_.push_back({ "3", "Title3", 33.3 });
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::list<Book>& books() const {
|
const std::list<Book>& books() const {
|
||||||
return books_;
|
return books_;
|
||||||
@@ -87,16 +88,39 @@ bool BookListService::Handle(const std::string& http_method,
|
|||||||
const std::string& request_content,
|
const std::string& request_content,
|
||||||
std::string* response_content) {
|
std::string* response_content) {
|
||||||
if (http_method == webcc::kHttpGet) {
|
if (http_method == webcc::kHttpGet) {
|
||||||
|
// Return all books as a JSON array.
|
||||||
|
|
||||||
Json::Value root(Json::arrayValue);
|
Json::Value root(Json::arrayValue);
|
||||||
for (const Book& book : g_book_store.books()) {
|
for (const Book& book : g_book_store.books()) {
|
||||||
root.append(book.ToJson());
|
root.append(book.ToJson());
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::StreamWriterBuilder wbuilder;
|
Json::StreamWriterBuilder builder;
|
||||||
*response_content = Json::writeString(wbuilder, root);
|
*response_content = Json::writeString(builder, root);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (http_method == webcc::kHttpPost) {
|
||||||
|
// Add a new book.
|
||||||
|
|
||||||
|
Json::Value root;
|
||||||
|
Json::CharReaderBuilder builder;
|
||||||
|
std::stringstream stream(request_content);
|
||||||
|
std::string errs;
|
||||||
|
if (!Json::parseFromStream(builder, stream, &root, &errs)) {
|
||||||
|
std::cerr << errs << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Book book;
|
||||||
|
book.id = root["id"].asString();
|
||||||
|
book.title = root["title"].asString();
|
||||||
|
book.price = root["price"].asDouble();
|
||||||
|
|
||||||
|
return g_book_store.AddBook(book);
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,8 +143,8 @@ bool BookDetailService::Handle(const std::string& http_method,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Json::StreamWriterBuilder wbuilder;
|
Json::StreamWriterBuilder builder;
|
||||||
*response_content = Json::writeString(wbuilder, book.ToJson());
|
*response_content = Json::writeString(builder, book.ToJson());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|||||||
+11
-21
@@ -43,32 +43,22 @@ public:
|
|||||||
SetHeader(kContentType, content_type);
|
SetHeader(kContentType, content_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetContent(std::string&& content) {
|
||||||
|
content_ = std::move(content);
|
||||||
|
SetContentLength(content_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetContent(const std::string& content) {
|
||||||
|
content_ = content;
|
||||||
|
SetContentLength(content_.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
void SetContentLength(std::size_t content_length) {
|
void SetContentLength(std::size_t content_length) {
|
||||||
content_length_ = content_length;
|
content_length_ = content_length;
|
||||||
SetHeader(kContentLength, std::to_string(content_length));
|
SetHeader(kContentLength, std::to_string(content_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use move semantics to avoid copy.
|
|
||||||
void set_content(std::string&& content) {
|
|
||||||
content_ = std::move(content);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppendContent(const char* data, std::size_t count) {
|
|
||||||
content_.append(data, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AppendContent(const std::string& data) {
|
|
||||||
content_.append(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsContentFull() const {
|
|
||||||
return IsContentLengthValid() && content_.length() >= content_length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsContentLengthValid() const {
|
|
||||||
return content_length_ != kInvalidLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Start line with trailing "\r\n".
|
// Start line with trailing "\r\n".
|
||||||
std::string start_line_;
|
std::string start_line_;
|
||||||
|
|||||||
+29
-12
@@ -9,6 +9,7 @@ namespace webcc {
|
|||||||
|
|
||||||
HttpParser::HttpParser(HttpMessage* message)
|
HttpParser::HttpParser(HttpMessage* message)
|
||||||
: message_(message)
|
: message_(message)
|
||||||
|
, content_length_(kInvalidLength)
|
||||||
, start_line_parsed_(false)
|
, start_line_parsed_(false)
|
||||||
, content_length_parsed_(false)
|
, content_length_parsed_(false)
|
||||||
, header_parsed_(false)
|
, header_parsed_(false)
|
||||||
@@ -18,11 +19,11 @@ HttpParser::HttpParser(HttpMessage* message)
|
|||||||
Error HttpParser::Parse(const char* data, std::size_t len) {
|
Error HttpParser::Parse(const char* data, std::size_t len) {
|
||||||
if (header_parsed_) {
|
if (header_parsed_) {
|
||||||
// Add the data to the content.
|
// Add the data to the content.
|
||||||
message_->AppendContent(data, len);
|
AppendContent(data, len);
|
||||||
|
|
||||||
if (message_->IsContentFull()) {
|
if (IsContentFull()) {
|
||||||
// All content has been read.
|
// All content has been read.
|
||||||
finished_ = true;
|
Finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
return kNoError;
|
return kNoError;
|
||||||
@@ -66,22 +67,21 @@ Error HttpParser::Parse(const char* data, std::size_t len) {
|
|||||||
// Headers just ended.
|
// Headers just ended.
|
||||||
|
|
||||||
if (!content_length_parsed_) {
|
if (!content_length_parsed_) {
|
||||||
// No Content-Length, no content.
|
// No Content-Length, no content. (TODO: Support chucked data)
|
||||||
message_->SetContentLength(0);
|
Finish();
|
||||||
finished_ = true;
|
|
||||||
return kNoError;
|
return kNoError;
|
||||||
} else {
|
} else {
|
||||||
// Invalid Content-Length in the request.
|
// Invalid Content-Length in the request.
|
||||||
if (!message_->IsContentLengthValid()) {
|
if (content_length_ == kInvalidLength) {
|
||||||
return kHttpContentLengthError;
|
return kHttpContentLengthError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message_->AppendContent(pending_data_.substr(off));
|
AppendContent(pending_data_.substr(off));
|
||||||
|
|
||||||
if (message_->IsContentFull()) {
|
if (IsContentFull()) {
|
||||||
// All content has been read.
|
// All content has been read.
|
||||||
finished_ = true;
|
Finish();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Save the unparsed piece for next parsing.
|
// Save the unparsed piece for next parsing.
|
||||||
@@ -110,11 +110,28 @@ void HttpParser::ParseContentLength(const std::string& line) {
|
|||||||
std::string value = line.substr(pos);
|
std::string value = line.substr(pos);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::size_t length = boost::lexical_cast<std::size_t>(value);
|
content_length_ = boost::lexical_cast<std::size_t>(value);
|
||||||
message_->SetContentLength(length);
|
|
||||||
} catch (boost::bad_lexical_cast&) {
|
} catch (boost::bad_lexical_cast&) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpParser::Finish() {
|
||||||
|
message_->SetContent(content_);
|
||||||
|
finished_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpParser::AppendContent(const char* data, std::size_t count) {
|
||||||
|
content_.append(data, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpParser::AppendContent(const std::string& data) {
|
||||||
|
content_.append(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpParser::IsContentFull() const {
|
||||||
|
return content_length_ != kInvalidLength &&
|
||||||
|
content_length_ <= content_.length();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace webcc
|
} // namespace webcc
|
||||||
|
|||||||
+14
-1
@@ -13,6 +13,10 @@ class HttpParser {
|
|||||||
public:
|
public:
|
||||||
explicit HttpParser(HttpMessage* message);
|
explicit HttpParser(HttpMessage* message);
|
||||||
|
|
||||||
|
~HttpParser() = default;
|
||||||
|
HttpParser(const HttpParser&) = delete;
|
||||||
|
HttpParser& operator=(const HttpParser&) = delete;
|
||||||
|
|
||||||
bool finished() const {
|
bool finished() const {
|
||||||
return finished_;
|
return finished_;
|
||||||
}
|
}
|
||||||
@@ -25,6 +29,13 @@ protected:
|
|||||||
|
|
||||||
void ParseContentLength(const std::string& line);
|
void ParseContentLength(const std::string& line);
|
||||||
|
|
||||||
|
void Finish();
|
||||||
|
|
||||||
|
void AppendContent(const char* data, std::size_t count);
|
||||||
|
void AppendContent(const std::string& data);
|
||||||
|
|
||||||
|
bool IsContentFull() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The result HTTP message.
|
// The result HTTP message.
|
||||||
HttpMessage* message_;
|
HttpMessage* message_;
|
||||||
@@ -34,7 +45,9 @@ protected:
|
|||||||
// Data waiting to be parsed.
|
// Data waiting to be parsed.
|
||||||
std::string pending_data_;
|
std::string pending_data_;
|
||||||
|
|
||||||
// Parsing helper flags.
|
// Temporary data and helper flags for parsing.
|
||||||
|
std::size_t content_length_;
|
||||||
|
std::string content_;
|
||||||
bool start_line_parsed_;
|
bool start_line_parsed_;
|
||||||
bool content_length_parsed_;
|
bool content_length_parsed_;
|
||||||
bool header_parsed_;
|
bool header_parsed_;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ std::vector<boost::asio::const_buffer> HttpResponse::ToBuffers() const {
|
|||||||
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
buffers.push_back(boost::asio::buffer(misc_strings::CRLF));
|
||||||
|
|
||||||
// Content (optional)
|
// Content (optional)
|
||||||
if (IsContentLengthValid()) {
|
if (!content_.empty()) {
|
||||||
buffers.push_back(boost::asio::buffer(content_));
|
buffers.push_back(boost::asio::buffer(content_));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ void HttpSession::SetResponseContent(const std::string& content_type,
|
|||||||
std::size_t content_length,
|
std::size_t content_length,
|
||||||
std::string&& content) {
|
std::string&& content) {
|
||||||
response_.SetContentType(content_type);
|
response_.SetContentType(content_type);
|
||||||
response_.SetContentLength(content.length());
|
response_.SetContent(std::move(content));
|
||||||
response_.set_content(std::move(content));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpSession::SendResponse() {
|
void HttpSession::SendResponse() {
|
||||||
|
|||||||
@@ -40,11 +40,9 @@ Error SoapClient::Call(const std::string& operation,
|
|||||||
http_request.set_method(kHttpPost);
|
http_request.set_method(kHttpPost);
|
||||||
http_request.set_url(url_);
|
http_request.set_url(url_);
|
||||||
http_request.SetContentType(kTextXmlUtf8);
|
http_request.SetContentType(kTextXmlUtf8);
|
||||||
http_request.SetContentLength(http_content.size());
|
http_request.SetContent(std::move(http_content));
|
||||||
http_request.SetHost(host_, port_);
|
http_request.SetHost(host_, port_);
|
||||||
http_request.SetHeader(kSoapAction, operation);
|
http_request.SetHeader(kSoapAction, operation);
|
||||||
http_request.set_content(std::move(http_content));
|
|
||||||
|
|
||||||
http_request.Build();
|
http_request.Build();
|
||||||
|
|
||||||
HttpResponse http_response;
|
HttpResponse http_response;
|
||||||
|
|||||||
Reference in New Issue
Block a user