Post a file with data streaming
This commit is contained in:
@@ -187,7 +187,7 @@ int main() {
|
||||
|
||||
server.Route("/", std::make_shared<HelloView>());
|
||||
|
||||
server.Start();
|
||||
server.Run();
|
||||
|
||||
} catch (const std::exception&) {
|
||||
return 1;
|
||||
@@ -274,8 +274,8 @@ The detailed implementation is out of the scope of this README, but here is an e
|
||||
```cpp
|
||||
webcc::ResponsePtr BookDetailView::Get(webcc::RequestPtr request) {
|
||||
if (request->args().size() != 1) {
|
||||
// Using kNotFound means the resource specified by the URL cannot be found.
|
||||
// kBadRequest could be another choice.
|
||||
// NotFound means the resource specified by the URL cannot be found.
|
||||
// BadRequest could be another choice.
|
||||
return webcc::ResponseBuilder{}.NotFound()();
|
||||
}
|
||||
|
||||
@@ -290,7 +290,8 @@ webcc::ResponsePtr BookDetailView::Get(webcc::RequestPtr request) {
|
||||
}
|
||||
|
||||
// Convert the book to JSON string and set as response data.
|
||||
return webcc::ResponseBuilder{}.OK().Data(<JsonStringOfTheBook>).Json().Utf8();
|
||||
return webcc::ResponseBuilder{}.OK().Data(<JsonStringOfTheBook>).
|
||||
Json().Utf8()();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
+188
-126
@@ -3,6 +3,7 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "boost/algorithm/string.hpp"
|
||||
#include "boost/filesystem/fstream.hpp"
|
||||
#include "boost/filesystem/operations.hpp"
|
||||
|
||||
#include "json/json.h"
|
||||
@@ -10,6 +11,8 @@
|
||||
#include "webcc/client_session.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// JSON helper functions (based on jsoncpp).
|
||||
@@ -30,7 +33,7 @@ static Json::Value StringToJson(const std::string& str) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
TEST(ClientTest, Head_RequestFunc) {
|
||||
TEST(ClientTest, Head) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
@@ -115,7 +118,7 @@ static void AssertGet(webcc::ResponsePtr r) {
|
||||
#endif // WEBCC_ENABLE_GZIP
|
||||
}
|
||||
|
||||
TEST(ClientTest, Get_RequestFunc) {
|
||||
TEST(ClientTest, Get) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
@@ -169,127 +172,15 @@ TEST(ClientTest, Get_SSL) {
|
||||
}
|
||||
#endif // WEBCC_ENABLE_SSL
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
#if WEBCC_ENABLE_GZIP
|
||||
|
||||
// Test Gzip compressed response.
|
||||
TEST(ClientTest, Compression_Gzip) {
|
||||
// Get a JPEG image (without streaming).
|
||||
TEST(ClientTest, Get_Jpeg_NoStream) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
auto r = session.Get("http://httpbin.org/gzip");
|
||||
|
||||
Json::Value json = StringToJson(r->data());
|
||||
|
||||
EXPECT_EQ(true, json["gzipped"].asBool());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Test Deflate compressed response.
|
||||
TEST(ClientTest, Compression_Deflate) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
auto r = session.Get("http://httpbin.org/deflate");
|
||||
|
||||
Json::Value json = StringToJson(r->data());
|
||||
|
||||
EXPECT_EQ(true, json["deflated"].asBool());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Test trying to compress the request.
|
||||
// TODO
|
||||
TEST(ClientTest, Compression_Request) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
const std::string data = "{'name'='Adam', 'age'=20}";
|
||||
|
||||
// This doesn't really compress the body!
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Post("http://httpbin.org/post").
|
||||
Body(data).Json().
|
||||
Gzip()
|
||||
Get("http://httpbin.org/image/jpeg")
|
||||
());
|
||||
|
||||
//Json::Value json = StringToJson(r->data());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // WEBCC_ENABLE_GZIP
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Test persistent (keep-alive) connections.
|
||||
//
|
||||
// NOTE:
|
||||
// Boost.org doesn't support persistent connection and always includes
|
||||
// "Connection: Close" header in the response.
|
||||
// Both Google and GitHub support persistent connection but they don't like
|
||||
// to include "Connection: Keep-Alive" header in the responses.
|
||||
// URLs:
|
||||
// "http://httpbin.org/get";
|
||||
// "https://www.boost.org/LICENSE_1_0.txt";
|
||||
// "https://www.google.com";
|
||||
// "https://api.github.com/events";
|
||||
//
|
||||
TEST(ClientTest, KeepAlive) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
std::string url = "http://httpbin.org/get";
|
||||
try {
|
||||
|
||||
// Keep-Alive by default.
|
||||
auto r = session.Get(url);
|
||||
|
||||
using boost::iequals;
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
|
||||
|
||||
// Close by setting Connection header.
|
||||
r = session.Get(url, {}, { "Connection", "Close" });
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
|
||||
|
||||
// Close by using request builder.
|
||||
r = session.Request(webcc::RequestBuilder{}.
|
||||
Get(url).KeepAlive(false)
|
||||
());
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
|
||||
|
||||
// Keep-Alive explicitly by using request builder.
|
||||
r = session.Request(webcc::RequestBuilder{}.
|
||||
Get(url).KeepAlive(true)
|
||||
());
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Get a JPEG image (without streaming).
|
||||
TEST(ClientTest, GetImageJpeg_NoStream) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
|
||||
auto r = session.Get("http://httpbin.org/image/jpeg");
|
||||
|
||||
// TODO: Verify the response is a valid JPEG image.
|
||||
//std::ofstream ofs(<path>, std::ios::binary);
|
||||
//ofs << r->data();
|
||||
@@ -299,16 +190,13 @@ TEST(ClientTest, GetImageJpeg_NoStream) {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Streaming
|
||||
|
||||
TEST(ClientTest, Stream_GetImageJpeg) {
|
||||
TEST(ClientTest, Get_Jpeg_Stream) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Get("http://httpbin.org/image/jpeg")(),
|
||||
Get("http://httpbin.org/image/jpeg")
|
||||
(),
|
||||
true);
|
||||
|
||||
auto file_body = r->file_body();
|
||||
@@ -338,7 +226,7 @@ TEST(ClientTest, Stream_GetImageJpeg) {
|
||||
|
||||
// Test whether the streamed file will be deleted or not at the end if it's
|
||||
// not moved to another path by the user.
|
||||
TEST(ClientTest, Stream_GetImageJpeg_NoMove) {
|
||||
TEST(ClientTest, Get_Jpeg_Stream_NoMove) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
@@ -346,7 +234,8 @@ TEST(ClientTest, Stream_GetImageJpeg_NoMove) {
|
||||
|
||||
{
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Get("http://httpbin.org/image/jpeg")(),
|
||||
Get("http://httpbin.org/image/jpeg")
|
||||
(),
|
||||
true);
|
||||
|
||||
auto file_body = r->file_body();
|
||||
@@ -369,7 +258,49 @@ TEST(ClientTest, Stream_GetImageJpeg_NoMove) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
TEST(ClientTest, Post_RequestFunc) {
|
||||
#if WEBCC_ENABLE_GZIP
|
||||
// Test Gzip compressed response.
|
||||
TEST(ClientTest, Get_Gzip) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Get("http://httpbin.org/gzip")
|
||||
());
|
||||
|
||||
Json::Value json = StringToJson(r->data());
|
||||
|
||||
EXPECT_EQ(true, json["gzipped"].asBool());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // WEBCC_ENABLE_GZIP
|
||||
|
||||
#if WEBCC_ENABLE_GZIP
|
||||
// Test Deflate compressed response.
|
||||
TEST(ClientTest, Get_Deflate) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Get("http://httpbin.org/deflate")
|
||||
());
|
||||
|
||||
Json::Value json = StringToJson(r->data());
|
||||
|
||||
EXPECT_EQ(true, json["deflated"].asBool());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // WEBCC_ENABLE_GZIP
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
TEST(ClientTest, Post) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
@@ -412,6 +343,80 @@ TEST(ClientTest, Post_Shortcut) {
|
||||
}
|
||||
}
|
||||
|
||||
static bfs::path GenerateTempFile(const std::string& data) {
|
||||
try {
|
||||
bfs::path path = bfs::temp_directory_path() / bfs::unique_path();
|
||||
|
||||
bfs::ofstream ofs;
|
||||
ofs.open(path, std::ios::binary);
|
||||
if (ofs.fail()) {
|
||||
return bfs::path{};
|
||||
}
|
||||
|
||||
ofs << data;
|
||||
|
||||
return path;
|
||||
|
||||
} catch (const bfs::filesystem_error&) {
|
||||
return bfs::path{};
|
||||
}
|
||||
}
|
||||
|
||||
TEST(ClientTest, Post_FileBody) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
const std::string data = "{'name'='Adam', 'age'=20}";
|
||||
|
||||
auto path = GenerateTempFile(data);
|
||||
if (path.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Post("http://httpbin.org/post").
|
||||
File(path) // Use the file as body
|
||||
());
|
||||
|
||||
EXPECT_EQ(webcc::Status::kOK, r->status());
|
||||
EXPECT_EQ("OK", r->reason());
|
||||
|
||||
Json::Value json = StringToJson(r->data());
|
||||
|
||||
EXPECT_EQ(data, json["data"].asString());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
|
||||
// Remove the temp file.
|
||||
boost::system::error_code ec;
|
||||
bfs::remove(path, ec);
|
||||
}
|
||||
|
||||
#if WEBCC_ENABLE_GZIP
|
||||
TEST(ClientTest, Post_Gzip_SmallData) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
try {
|
||||
// This data is too small to be compressed.
|
||||
const std::string data = "{'name'='Adam', 'age'=20}";
|
||||
|
||||
// This doesn't really compress the body!
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Post("http://httpbin.org/post").
|
||||
Body(data).Json().
|
||||
Gzip()
|
||||
());
|
||||
|
||||
//Json::Value json = StringToJson(r->data());
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // WEBCC_ENABLE_GZIP
|
||||
|
||||
#if (WEBCC_ENABLE_GZIP && WEBCC_ENABLE_SSL)
|
||||
// NOTE: Most servers don't support compressed requests!
|
||||
TEST(ClientTest, Post_Gzip) {
|
||||
@@ -438,6 +443,63 @@ TEST(ClientTest, Post_Gzip) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Test persistent (keep-alive) connections.
|
||||
//
|
||||
// NOTE:
|
||||
// Boost.org doesn't support persistent connection and always includes
|
||||
// "Connection: Close" header in the response.
|
||||
// Both Google and GitHub support persistent connection but they don't like
|
||||
// to include "Connection: Keep-Alive" header in the responses.
|
||||
// URLs:
|
||||
// "http://httpbin.org/get";
|
||||
// "https://www.boost.org/LICENSE_1_0.txt";
|
||||
// "https://www.google.com";
|
||||
// "https://api.github.com/events";
|
||||
//
|
||||
TEST(ClientTest, KeepAlive) {
|
||||
webcc::ClientSession session;
|
||||
|
||||
const std::string url = "http://httpbin.org/get";
|
||||
|
||||
try {
|
||||
// Keep-Alive by default.
|
||||
auto r = session.Request(webcc::RequestBuilder{}.Get(url)());
|
||||
|
||||
using boost::iequals;
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
|
||||
|
||||
// Close by setting Connection header directly.
|
||||
r = session.Request(webcc::RequestBuilder{}.
|
||||
Get(url).
|
||||
Header("Connection", "Close")
|
||||
());
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
|
||||
|
||||
// Close by using request builder.
|
||||
r = session.Request(webcc::RequestBuilder{}.
|
||||
Get(url).
|
||||
KeepAlive(false)
|
||||
());
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close"));
|
||||
|
||||
// Keep-Alive explicitly by using request builder.
|
||||
r = session.Request(webcc::RequestBuilder{}.
|
||||
Get(url).
|
||||
KeepAlive(true)
|
||||
());
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
|
||||
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Set webcc::LOG_CONSOLE to enable logging.
|
||||
WEBCC_LOG_INIT("", 0);
|
||||
|
||||
@@ -6,18 +6,15 @@
|
||||
#include "webcc/client_session.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
void Help(const char* argv0) {
|
||||
std::cout << "Usage: file_downloader <url> <path>" << std::endl;
|
||||
std::cout << "E.g.," << std::endl;
|
||||
std::cout << " file_downloader http://httpbin.org/image/jpeg D:/test.jpg"
|
||||
<< std::endl;
|
||||
std::cout << " file_downloader https://www.google.com/favicon.ico"
|
||||
<< " D:/test.ico" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
Help(argv[0]);
|
||||
std::cout << "usage: file_downloader <url> <path>" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "examples:" << std::endl;
|
||||
std::cout << " $ file_downloader http://httpbin.org/image/jpeg D:/test.jpg"
|
||||
<< std::endl;
|
||||
std::cout << " $ file_downloader https://www.google.com/favicon.ico"
|
||||
<< " D:/test.ico" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,14 @@
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/server.h"
|
||||
|
||||
void Help() {
|
||||
std::cout << "Usage:" << std::endl;
|
||||
std::cout << " file_server <port> <doc_root> [chunk_size]" << std::endl;
|
||||
std::cout << "E.g.," << std::endl;
|
||||
std::cout << " file_server 8080 D:/www" << std::endl;
|
||||
std::cout << " file_server 8080 D:/www 10000" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 3) {
|
||||
Help();
|
||||
std::cout << "usage: file_server <port> <doc_root> [chunk_size]"
|
||||
<< std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "examples:" << std::endl;
|
||||
std::cout << " $ file_server 8080 D:/www" << std::endl;
|
||||
std::cout << " $ file_server 8080 D:/www 10000" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,20 +5,17 @@
|
||||
#include "webcc/client_session.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
void Help() {
|
||||
std::cout << "Usage:" << std::endl;
|
||||
std::cout << " file_upload_client <upload_dir> [url]" << std::endl;
|
||||
std::cout << "Default Url: http://httpbin.org/post" << std::endl;
|
||||
std::cout << "E.g.," << std::endl;
|
||||
std::cout << " file_upload_client E:/github/webcc/data/upload"
|
||||
<< std::endl;
|
||||
std::cout << " file_upload_client E:/github/webcc/data/upload"
|
||||
<< " http://httpbin.org/post" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
Help();
|
||||
std::cout << "usage: file_upload_client <upload_dir> [url]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "default url: http://httpbin.org/post" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "examples:" << std::endl;
|
||||
std::cout << " $ file_upload_client E:/github/webcc/data/upload"
|
||||
<< std::endl;
|
||||
std::cout << " $ file_upload_client E:/github/webcc/data/upload "
|
||||
<< "http://httpbin.org/post" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -45,8 +42,8 @@ int main(int argc, char* argv[]) {
|
||||
try {
|
||||
auto r = session.Request(webcc::RequestBuilder{}.
|
||||
Post(url).
|
||||
File("file", upload_dir / "remember.txt").
|
||||
Form("json", "{}", "application/json")
|
||||
FormFile("file", upload_dir / "remember.txt").
|
||||
FormData("json", "{}", "application/json")
|
||||
());
|
||||
|
||||
std::cout << r->status() << std::endl;
|
||||
|
||||
@@ -32,15 +32,9 @@ private:
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Help(const char* argv0) {
|
||||
std::cout << "Usage: " << argv0 << " <port>" << std::endl;
|
||||
std::cout << " E.g.," << std::endl;
|
||||
std::cout << " " << argv0 << " 8080" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
Help(argv[0]);
|
||||
std::cout << "usage: file_upload_server <port>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,17 +188,13 @@ void PrintBookList(const std::list<Book>& books) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Help() {
|
||||
std::cout << "Usage:" << std::endl;
|
||||
std::cout << " rest_book_client <url> [timeout]" << std::endl;
|
||||
std::cout << "E.g.," << std::endl;
|
||||
std::cout << " rest_book_client http://localhost:8080" << std::endl;
|
||||
std::cout << " rest_book_client http://localhost:8080 2" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
Help();
|
||||
std::cout << "usage: rest_book_client <url> [timeout]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "examples:" << std::endl;
|
||||
std::cout << " $ rest_book_client http://localhost:8080" << std::endl;
|
||||
std::cout << " $ rest_book_client http://localhost:8080 2" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,8 +145,8 @@ webcc::ResponsePtr BookDetailView::Get(webcc::RequestPtr request) {
|
||||
Sleep(sleep_seconds_);
|
||||
|
||||
if (request->args().size() != 1) {
|
||||
// Using kNotFound means the resource specified by the URL cannot be found.
|
||||
// kBadRequest could be another choice.
|
||||
// NotFound means the resource specified by the URL cannot be found.
|
||||
// BadRequest could be another choice.
|
||||
return webcc::ResponseBuilder{}.NotFound()();
|
||||
}
|
||||
|
||||
@@ -157,8 +157,8 @@ webcc::ResponsePtr BookDetailView::Get(webcc::RequestPtr request) {
|
||||
return webcc::ResponseBuilder{}.NotFound()();
|
||||
}
|
||||
|
||||
return webcc::ResponseBuilder{}.OK().Body(BookToJsonString(book)).Json().
|
||||
Utf8()();
|
||||
return webcc::ResponseBuilder{}.OK().Body(BookToJsonString(book)).
|
||||
Json().Utf8()();
|
||||
}
|
||||
|
||||
webcc::ResponsePtr BookDetailView::Put(webcc::RequestPtr request) {
|
||||
@@ -199,19 +199,17 @@ webcc::ResponsePtr BookDetailView::Delete(webcc::RequestPtr request) {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
void Help(const char* argv0) {
|
||||
std::cout << "Usage: " << argv0 << " <port> [seconds]" << std::endl;
|
||||
std::cout << "If |seconds| is provided, the server will sleep these seconds "
|
||||
"before sending back each response."
|
||||
<< std::endl;
|
||||
std::cout << " E.g.," << std::endl;
|
||||
std::cout << " " << argv0 << " 8080" << std::endl;
|
||||
std::cout << " " << argv0 << " 8080 3" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc < 2) {
|
||||
Help(argv[0]);
|
||||
std::cout << "usage: rest_book_server <port> [seconds]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "If |seconds| is provided, the server will sleep, for testing "
|
||||
<< "timeout, before " << std::endl
|
||||
<< "send back each response." << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "examples:" << std::endl;
|
||||
std::cout << " $ rest_book_server 8080" << std::endl;
|
||||
std::cout << " $ rest_book_server 8080 3" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+19
-10
@@ -51,20 +51,29 @@ RequestPtr RequestBuilder::operator()() {
|
||||
return request;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::File(const std::string& name,
|
||||
const Path& path,
|
||||
const std::string& media_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart::NewFile(name, path, media_type));
|
||||
RequestBuilder& RequestBuilder::File(const Path& path, bool infer_media_type,
|
||||
std::size_t chunk_size) {
|
||||
body_.reset(new FileBody{ path, chunk_size });
|
||||
|
||||
if (infer_media_type) {
|
||||
media_type_ = media_types::FromExtension(path.extension().string());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::Form(const std::string& name,
|
||||
std::string&& data,
|
||||
const std::string& media_type) {
|
||||
RequestBuilder& RequestBuilder::FormFile(const std::string& name,
|
||||
const Path& path,
|
||||
const std::string& media_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart::New(name, std::move(data), media_type));
|
||||
return *this;
|
||||
return Form(FormPart::NewFile(name, path, media_type));
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::FormData(const std::string& name,
|
||||
std::string&& data,
|
||||
const std::string& media_type) {
|
||||
assert(!name.empty());
|
||||
return Form(FormPart::New(name, std::move(data), media_type));
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::Auth(const std::string& type,
|
||||
|
||||
+11
-5
@@ -95,17 +95,23 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Add a file to upload.
|
||||
RequestBuilder& File(const std::string& name, const Path& path,
|
||||
const std::string& media_type = "");
|
||||
// Use the file content as body.
|
||||
RequestBuilder& File(const Path& path, bool infer_media_type = true,
|
||||
std::size_t chunk_size = 1024);
|
||||
|
||||
// Add a form part.
|
||||
RequestBuilder& Form(FormPartPtr part) {
|
||||
form_parts_.push_back(part);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Form(const std::string& name, std::string&& data,
|
||||
const std::string& media_type = "");
|
||||
// Add a form part of file.
|
||||
RequestBuilder& FormFile(const std::string& name, const Path& path,
|
||||
const std::string& media_type = "");
|
||||
|
||||
// Add a form part of string data.
|
||||
RequestBuilder& FormData(const std::string& name, std::string&& data,
|
||||
const std::string& media_type = "");
|
||||
|
||||
RequestBuilder& Header(const std::string& key, const std::string& value) {
|
||||
headers_.push_back(key);
|
||||
|
||||
Reference in New Issue
Block a user