Changed set_file_content to accept only a regular file path.
This commit is contained in:
parent
3f2922b3fa
commit
7ab9c119ef
164
README.md
164
README.md
@ -97,37 +97,33 @@ int main(void)
|
|||||||
|
|
||||||
Server svr;
|
Server svr;
|
||||||
|
|
||||||
svr.Get("/hi", [](const Request& req, Response& res) {
|
svr.Get("/hi", [](const Request &req, Response &res) {
|
||||||
res.set_content("Hello World!", "text/plain");
|
res.set_content("Hello World!", "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Match the request path against a regular expression
|
// Match the request path against a regular expression
|
||||||
// and extract its captures
|
// and extract its captures
|
||||||
svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) {
|
svr.Get(R"(/numbers/(\d+))", [&](const Request &req, Response &res) {
|
||||||
auto numbers = req.matches[1];
|
auto numbers = req.matches[1];
|
||||||
res.set_content(numbers, "text/plain");
|
res.set_content(numbers, "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Capture the second segment of the request path as "id" path param
|
// Capture the second segment of the request path as "id" path param
|
||||||
svr.Get("/users/:id", [&](const Request& req, Response& res) {
|
svr.Get("/users/:id", [&](const Request &req, Response &res) {
|
||||||
auto user_id = req.path_params.at("id");
|
auto user_id = req.path_params.at("id");
|
||||||
res.set_content(user_id, "text/plain");
|
res.set_content(user_id, "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
// Extract values from HTTP headers and URL query params
|
// Extract values from HTTP headers and URL query params
|
||||||
svr.Get("/body-header-param", [](const Request& req, Response& res) {
|
svr.Get("/body-header-param", [](const Request &req, Response &res) {
|
||||||
if (req.has_header("Content-Length")) {
|
if (req.has_header("Content-Length")) {
|
||||||
auto val = req.get_header_value("Content-Length");
|
auto val = req.get_header_value("Content-Length");
|
||||||
}
|
}
|
||||||
if (req.has_param("key")) {
|
if (req.has_param("key")) { auto val = req.get_param_value("key"); }
|
||||||
auto val = req.get_param_value("key");
|
|
||||||
}
|
|
||||||
res.set_content(req.body, "text/plain");
|
res.set_content(req.body, "text/plain");
|
||||||
});
|
});
|
||||||
|
|
||||||
svr.Get("/stop", [&](const Request& req, Response& res) {
|
svr.Get("/stop", [&](const Request &req, Response &res) { svr.stop(); });
|
||||||
svr.stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
svr.listen("localhost", 1234);
|
svr.listen("localhost", 1234);
|
||||||
}
|
}
|
||||||
@ -276,7 +272,7 @@ svr.set_post_routing_handler([](const auto& req, auto& res) {
|
|||||||
svr.Post("/multipart", [&](const auto& req, auto& res) {
|
svr.Post("/multipart", [&](const auto& req, auto& res) {
|
||||||
auto size = req.files.size();
|
auto size = req.files.size();
|
||||||
auto ret = req.has_file("name1");
|
auto ret = req.has_file("name1");
|
||||||
const auto& file = req.get_file_value("name1");
|
const auto &file = req.get_file_value("name1");
|
||||||
// file.filename;
|
// file.filename;
|
||||||
// file.content_type;
|
// file.content_type;
|
||||||
// file.content;
|
// file.content;
|
||||||
@ -288,10 +284,10 @@ svr.Post("/multipart", [&](const auto& req, auto& res) {
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Post("/content_receiver",
|
svr.Post("/content_receiver",
|
||||||
[&](const Request &req, Response &res, const ContentReader &content_reader) {
|
[&](const Request &req, Response &res, const ContentReader &content_reader) {
|
||||||
if (req.is_multipart_form_data()) {
|
if (req.is_multipart_form_data()) {
|
||||||
// NOTE: `content_reader` is blocking until every form data field is read
|
// NOTE: `content_reader` is blocking until every form data field is read
|
||||||
MultipartFormDataItems files;
|
MultipartFormDataItems files;
|
||||||
content_reader(
|
content_reader(
|
||||||
[&](const MultipartFormData &file) {
|
[&](const MultipartFormData &file) {
|
||||||
files.push_back(file);
|
files.push_back(file);
|
||||||
return true;
|
return true;
|
||||||
@ -300,13 +296,13 @@ svr.Post("/content_receiver",
|
|||||||
files.back().content.append(data, data_length);
|
files.back().content.append(data, data_length);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
std::string body;
|
std::string body;
|
||||||
content_reader([&](const char *data, size_t data_length) {
|
content_reader([&](const char *data, size_t data_length) {
|
||||||
body.append(data, data_length);
|
body.append(data, data_length);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -319,14 +315,14 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
auto data = new std::string("abcdefg");
|
auto data = new std::string("abcdefg");
|
||||||
|
|
||||||
res.set_content_provider(
|
res.set_content_provider(
|
||||||
data->size(), // Content length
|
data->size(), // Content length
|
||||||
"text/plain", // Content type
|
"text/plain", // Content type
|
||||||
[&, data](size_t offset, size_t length, DataSink &sink) {
|
[&, data](size_t offset, size_t length, DataSink &sink) {
|
||||||
const auto &d = *data;
|
const auto &d = *data;
|
||||||
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
sink.write(&d[offset], std::min(length, DATA_CHUNK_SIZE));
|
||||||
return true; // return 'false' if you want to cancel the process.
|
return true; // return 'false' if you want to cancel the process.
|
||||||
},
|
},
|
||||||
[data](bool success) { delete data; });
|
[data](bool success) { delete data; });
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -335,17 +331,17 @@ Without content length:
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Get("/stream", [&](const Request &req, Response &res) {
|
svr.Get("/stream", [&](const Request &req, Response &res) {
|
||||||
res.set_content_provider(
|
res.set_content_provider(
|
||||||
"text/plain", // Content type
|
"text/plain", // Content type
|
||||||
[&](size_t offset, DataSink &sink) {
|
[&](size_t offset, DataSink &sink) {
|
||||||
if (/* there is still data */) {
|
if (/* there is still data */) {
|
||||||
std::vector<char> data;
|
std::vector<char> data;
|
||||||
// prepare data...
|
// prepare data...
|
||||||
sink.write(data.data(), data.size());
|
sink.write(data.data(), data.size());
|
||||||
} else {
|
} else {
|
||||||
sink.done(); // No more data
|
sink.done(); // No more data
|
||||||
}
|
}
|
||||||
return true; // return 'false' if you want to cancel the process.
|
return true; // return 'false' if you want to cancel the process.
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -354,15 +350,13 @@ svr.Get("/stream", [&](const Request &req, Response &res) {
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||||
res.set_chunked_content_provider(
|
res.set_chunked_content_provider(
|
||||||
"text/plain",
|
"text/plain", [](size_t offset, DataSink &sink) {
|
||||||
[](size_t offset, DataSink &sink) {
|
sink.write("123", 3);
|
||||||
sink.write("123", 3);
|
sink.write("345", 3);
|
||||||
sink.write("345", 3);
|
sink.write("789", 3);
|
||||||
sink.write("789", 3);
|
sink.done(); // No more data
|
||||||
sink.done(); // No more data
|
return true; // return 'false' if you want to cancel the process.
|
||||||
return true; // return 'false' if you want to cancel the process.
|
});
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -371,24 +365,21 @@ With trailer:
|
|||||||
```cpp
|
```cpp
|
||||||
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
svr.Get("/chunked", [&](const Request& req, Response& res) {
|
||||||
res.set_header("Trailer", "Dummy1, Dummy2");
|
res.set_header("Trailer", "Dummy1, Dummy2");
|
||||||
res.set_chunked_content_provider(
|
res.set_chunked_content_provider("text/plain", [](size_t offset,
|
||||||
"text/plain",
|
DataSink &sink) {
|
||||||
[](size_t offset, DataSink &sink) {
|
sink.write("123", 3);
|
||||||
sink.write("123", 3);
|
sink.write("345", 3);
|
||||||
sink.write("345", 3);
|
sink.write("789", 3);
|
||||||
sink.write("789", 3);
|
sink.done_with_trailer({{"Dummy1", "DummyVal1"}, {"Dummy2", "DummyVal2"}});
|
||||||
sink.done_with_trailer({
|
return true;
|
||||||
{"Dummy1", "DummyVal1"},
|
});
|
||||||
{"Dummy2", "DummyVal2"}
|
|
||||||
});
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Send file content
|
### Send file content
|
||||||
|
|
||||||
|
We can set a file path for the response body. It's a user's responsibility to pass a valid regular file path. If the path doesn't exist, or a directory path, cpp-httplib throws an exception.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.Get("/content", [&](const Request &req, Response &res) {
|
svr.Get("/content", [&](const Request &req, Response &res) {
|
||||||
res.set_file_content("./path/to/conent.html");
|
res.set_file_content("./path/to/conent.html");
|
||||||
@ -452,7 +443,8 @@ Please see [Server example](https://github.com/yhirose/cpp-httplib/blob/master/e
|
|||||||
If you want to set the thread count at runtime, there is no convenient way... But here is how.
|
If you want to set the thread count at runtime, there is no convenient way... But here is how.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.new_task_queue = [] { return new ThreadPool(12); };
|
svr.new_task_queue = [] {
|
||||||
|
return new ThreadPool(12); };
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also provide an optional parameter to limit the maximum number
|
You can also provide an optional parameter to limit the maximum number
|
||||||
@ -460,7 +452,8 @@ of pending requests, i.e. requests `accept()`ed by the listener but
|
|||||||
still waiting to be serviced by worker threads.
|
still waiting to be serviced by worker threads.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
svr.new_task_queue = [] { return new ThreadPool(/*num_threads=*/12, /*max_queued_requests=*/18); };
|
svr.new_task_queue = [] {
|
||||||
|
return new ThreadPool(/*num_threads=*/12, /*max_queued_requests=*/18); };
|
||||||
```
|
```
|
||||||
|
|
||||||
Default limit is 0 (unlimited). Once the limit is reached, the listener
|
Default limit is 0 (unlimited). Once the limit is reached, the listener
|
||||||
@ -473,9 +466,7 @@ You can supply your own thread pool implementation according to your need.
|
|||||||
```cpp
|
```cpp
|
||||||
class YourThreadPoolTaskQueue : public TaskQueue {
|
class YourThreadPoolTaskQueue : public TaskQueue {
|
||||||
public:
|
public:
|
||||||
YourThreadPoolTaskQueue(size_t n) {
|
YourThreadPoolTaskQueue(size_t n) { pool_.start_with_thread_count(n); }
|
||||||
pool_.start_with_thread_count(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool enqueue(std::function<void()> fn) override {
|
virtual bool enqueue(std::function<void()> fn) override {
|
||||||
/* Return true if the task was actually enqueued, or false
|
/* Return true if the task was actually enqueued, or false
|
||||||
@ -483,9 +474,7 @@ public:
|
|||||||
return pool_.enqueue(fn);
|
return pool_.enqueue(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void shutdown() override {
|
virtual void shutdown() override { pool_.shutdown_gracefully(); }
|
||||||
pool_.shutdown_gracefully();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
YourThreadPool pool_;
|
YourThreadPool pool_;
|
||||||
@ -648,8 +637,8 @@ std::string body;
|
|||||||
|
|
||||||
auto res = cli.Get("/large-data",
|
auto res = cli.Get("/large-data",
|
||||||
[&](const char *data, size_t data_length) {
|
[&](const char *data, size_t data_length) {
|
||||||
body.append(data, data_length);
|
body.append(data, data_length);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -659,12 +648,12 @@ std::string body;
|
|||||||
auto res = cli.Get(
|
auto res = cli.Get(
|
||||||
"/stream", Headers(),
|
"/stream", Headers(),
|
||||||
[&](const Response &response) {
|
[&](const Response &response) {
|
||||||
EXPECT_EQ(StatusCode::OK_200, response.status);
|
EXPECT_EQ(StatusCode::OK_200, response.status);
|
||||||
return true; // return 'false' if you want to cancel the request.
|
return true; // return 'false' if you want to cancel the request.
|
||||||
},
|
},
|
||||||
[&](const char *data, size_t data_length) {
|
[&](const char *data, size_t data_length) {
|
||||||
body.append(data, data_length);
|
body.append(data, data_length);
|
||||||
return true; // return 'false' if you want to cancel the request.
|
return true; // return 'false' if you want to cancel the request.
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -676,8 +665,8 @@ std::string body = ...;
|
|||||||
auto res = cli.Post(
|
auto res = cli.Post(
|
||||||
"/stream", body.size(),
|
"/stream", body.size(),
|
||||||
[](size_t offset, size_t length, DataSink &sink) {
|
[](size_t offset, size_t length, DataSink &sink) {
|
||||||
sink.write(body.data() + offset, length);
|
sink.write(body.data() + offset, length);
|
||||||
return true; // return 'false' if you want to cancel the request.
|
return true; // return 'false' if you want to cancel the request.
|
||||||
},
|
},
|
||||||
"text/plain");
|
"text/plain");
|
||||||
```
|
```
|
||||||
@ -688,11 +677,11 @@ auto res = cli.Post(
|
|||||||
auto res = cli.Post(
|
auto res = cli.Post(
|
||||||
"/stream",
|
"/stream",
|
||||||
[](size_t offset, DataSink &sink) {
|
[](size_t offset, DataSink &sink) {
|
||||||
sink.os << "chunked data 1";
|
sink.os << "chunked data 1";
|
||||||
sink.os << "chunked data 2";
|
sink.os << "chunked data 2";
|
||||||
sink.os << "chunked data 3";
|
sink.os << "chunked data 3";
|
||||||
sink.done();
|
sink.done();
|
||||||
return true; // return 'false' if you want to cancel the request.
|
return true; // return 'false' if you want to cancel the request.
|
||||||
},
|
},
|
||||||
"text/plain");
|
"text/plain");
|
||||||
```
|
```
|
||||||
@ -704,9 +693,8 @@ httplib::Client cli(url, port);
|
|||||||
|
|
||||||
// prints: 0 / 000 bytes => 50% complete
|
// prints: 0 / 000 bytes => 50% complete
|
||||||
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
|
auto res = cli.Get("/", [](uint64_t len, uint64_t total) {
|
||||||
printf("%lld / %lld bytes => %d%% complete\n",
|
printf("%lld / %lld bytes => %d%% complete\n", len, total,
|
||||||
len, total,
|
(int)(len * 100 / total));
|
||||||
(int)(len*100/total));
|
|
||||||
return true; // return 'false' if you want to cancel the request.
|
return true; // return 'false' if you want to cancel the request.
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -904,8 +892,8 @@ g++ 4.8 and below cannot build this library since `<regex>` in the versions are
|
|||||||
Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32_LEAN_AND_MEAN` beforehand.
|
Include `httplib.h` before `Windows.h` or include `Windows.h` by defining `WIN32_LEAN_AND_MEAN` beforehand.
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
#include <httplib.h>
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <httplib.h>
|
||||||
```
|
```
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
15
httplib.h
15
httplib.h
@ -5752,12 +5752,21 @@ inline void Response::set_chunked_content_provider(
|
|||||||
|
|
||||||
inline void Response::set_file_content(const std::string &path,
|
inline void Response::set_file_content(const std::string &path,
|
||||||
const std::string &content_type) {
|
const std::string &content_type) {
|
||||||
file_content_path_ = path;
|
detail::FileStat stat(dir);
|
||||||
file_content_content_type_ = content_type;
|
if (stat.is_file(path)) {
|
||||||
|
file_content_path_ = path;
|
||||||
|
file_content_content_type_ = content_type;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CPPHTTPLIB_NO_EXCEPTIONS
|
||||||
|
std::string msg = "'" + path + "' is not a regular file.";
|
||||||
|
throw std::invalid_argument(msg);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Response::set_file_content(const std::string &path) {
|
inline void Response::set_file_content(const std::string &path) {
|
||||||
file_content_path_ = path;
|
return set_file_content(path, std::string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Result implementation
|
// Result implementation
|
||||||
|
@ -2288,6 +2288,8 @@ protected:
|
|||||||
{
|
{
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
cli_.enable_server_certificate_verification(false);
|
cli_.enable_server_certificate_verification(false);
|
||||||
|
#else
|
||||||
|
#error no ssl
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user