Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

utf8 path #488

Merged
merged 8 commits into from
Jan 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/cinatra/coro_http_client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1186,6 +1186,9 @@ class coro_http_client : public std::enable_shared_from_this<coro_http_client> {
std::pair<bool, uri_t> handle_uri(resp_data &data, const S &uri) {
uri_t u;
if (!u.parse_from(uri.data())) {
CINATRA_LOG_WARNING
<< uri
<< ", the url is not right, maybe need to encode the url firstly";
data.net_err = std::make_error_code(std::errc::protocol_error);
data.status = 404;
return {false, {}};
Expand Down
6 changes: 6 additions & 0 deletions include/cinatra/coro_http_connection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ class coro_http_connection
parser_.method().data(),
parser_.method().length() + 1 + parser_.url().length()};

std::string decode_key;
if (parser_.url().find('%') != std::string_view::npos) {
decode_key = code_utils::url_decode(key);
key = decode_key;
}

if (!body_.empty()) {
request_.set_body(body_);
}
Expand Down
4 changes: 2 additions & 2 deletions include/cinatra/coro_http_server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,12 +228,12 @@ class coro_http_server {
}

std::filesystem::path router_path =
std::filesystem::path(static_dir_router_path_);
std::filesystem::u8path(static_dir_router_path_);

std::string uri;
for (auto &file : files_) {
auto relative_path =
std::filesystem::path(file.substr(static_dir_.length())).string();
std::filesystem::u8path(file.substr(static_dir_.length())).string();
if (size_t pos = relative_path.find('\\') != std::string::npos) {
replace_all(relative_path, "\\", "/");
}
Expand Down
46 changes: 31 additions & 15 deletions include/cinatra/url_encode_decode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,40 @@ inline static std::string url_encode(const std::string &value) noexcept {
return result;
}

inline static std::string url_decode(const std::string &value) noexcept {
inline static std::string url_decode(std::string_view str) noexcept {
std::string result;
result.reserve(value.size() / 3 +
(value.size() % 3)); // Minimum size of result

for (std::size_t i = 0; i < value.size(); ++i) {
auto &chr = value[i];
if (chr == '%' && i + 2 < value.size()) {
auto hex = value.substr(i + 1, 2);
auto decoded_chr =
static_cast<char>(std::strtol(hex.c_str(), nullptr, 16));
result += decoded_chr;
i += 2;
result.reserve(str.size());

for (size_t i = 0; i < str.size(); ++i) {
char ch = str[i];
if (ch == '%') {
constexpr char hex[] = "0123456789ABCDEF";

if (++i == str.size()) {
result.push_back('?');
break;
}

int hi = (int)(std::find(hex, hex + 16, toupper(str[i])) - hex);

if (++i == str.size()) {
result.push_back('?');
break;
}

int lo = (int)(std::find(hex, hex + 16, toupper(str[i])) - hex);

if ((hi >= 16) || (lo >= 16)) {
result.push_back('?');
break;
}

result.push_back((char)((hi << 4) + lo));
}
else if (chr == '+')
result += ' ';
else if (ch == '+')
result.push_back(' ');
else
result += chr;
result.push_back(ch);
}

return result;
Expand Down
41 changes: 38 additions & 3 deletions tests/test_coro_http_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,15 @@ TEST_CASE("coro_server example, will block") {
CHECK(server.port() > 0);
}

bool create_file(std::string_view filename, size_t file_size = 1024) {
std::ofstream out(filename.data(), std::ios::binary);
template <typename View>
bool create_file(View filename, size_t file_size = 1024) {
std::cout << "begin to open file: " << filename << "\n";
std::ofstream out(filename, std::ios::binary);
if (!out.is_open()) {
std::cout << "open file: " << filename << " failed\n";
return false;
}

std::cout << "open file: " << filename << " ok\n";
std::string str(file_size, 'A');
out.write(str.data(), str.size());
return true;
Expand Down Expand Up @@ -175,11 +178,43 @@ TEST_CASE("test multiple download") {

TEST_CASE("test range download") {
create_file("range_test.txt", 64);
#ifdef ASIO_WINDOWS
#else
create_file("中文测试.txt", 64);
create_file(fs::u8path("utf8中文.txt").string(), 64);
#endif
std::cout << fs::current_path() << "\n";
coro_http_server server(1, 9001);
server.set_static_res_dir("", "");
server.set_file_resp_format_type(file_resp_format_type::range);
server.async_start();
std::this_thread::sleep_for(300ms);

#ifdef ASIO_WINDOWS
#else
{
// test Chinese file name
coro_http_client client{};
std::string local_filename = "temp.txt";

std::string base_uri = "http://127.0.0.1:9001/";
std::string path = code_utils::url_encode("中文测试.txt");
auto result = client.download(base_uri + path, local_filename);
CHECK(result.status == 200);
CHECK(fs::file_size(local_filename) == 64);
}

{
coro_http_client client{};
std::string local_filename = "temp1.txt";
std::string base_uri = "http://127.0.0.1:9001/";
std::string path =
code_utils::url_encode(fs::u8path("utf8中文.txt").string());
auto result = client.download(base_uri + path, local_filename);
CHECK(result.status == 200);
CHECK(fs::file_size(local_filename) == 64);
}
#endif

coro_http_client client{};
std::string filename = "test1.txt";
Expand Down
Loading