refactor: remove tr_loadFile() (#3540)

* refactor: use the std::vector variant of tr_loadFile() in rpc-server.cc

* refactor: use the std::vector variant of tr_loadFile() in rename-test.cc

* refactor: remove the unused raw ptr variant of tr_loadFile()
This commit is contained in:
Charles Kerr 2022-07-28 14:22:32 -05:00 committed by GitHub
parent e491f9d215
commit e0ca366b2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 41 additions and 137 deletions

View File

@ -163,44 +163,46 @@ static char const* mimetype_guess(std::string_view path)
return "application/octet-stream";
}
static void add_response(struct evhttp_request* req, tr_rpc_server* server, struct evbuffer* out, struct evbuffer* content)
static evbuffer* make_response(struct evhttp_request* req, tr_rpc_server* server, std::string_view content)
{
auto* const out = evbuffer_new();
char const* key = "Accept-Encoding";
char const* encoding = evhttp_find_header(req->input_headers, key);
bool const do_compress = encoding != nullptr && strstr(encoding, "gzip") != nullptr;
if (!do_compress)
{
evbuffer_add_buffer(out, content);
evbuffer_add(out, std::data(content), std::size(content));
}
else
{
auto const* const content_ptr = evbuffer_pullup(content, -1);
size_t const content_len = evbuffer_get_length(content);
auto const max_compressed_len = libdeflate_deflate_compress_bound(server->compressor.get(), content_len);
auto const max_compressed_len = libdeflate_deflate_compress_bound(server->compressor.get(), std::size(content));
struct evbuffer_iovec iovec[1];
evbuffer_reserve_space(out, std::max(content_len, max_compressed_len), iovec, 1);
evbuffer_reserve_space(out, std::max(std::size(content), max_compressed_len), iovec, 1);
auto const compressed_len = libdeflate_gzip_compress(
server->compressor.get(),
content_ptr,
content_len,
std::data(content),
std::size(content),
iovec[0].iov_base,
iovec[0].iov_len);
if (0 < compressed_len && compressed_len < content_len)
if (0 < compressed_len && compressed_len < std::size(content))
{
iovec[0].iov_len = compressed_len;
evhttp_add_header(req->output_headers, "Content-Encoding", "gzip");
}
else
{
std::copy_n(content_ptr, content_len, static_cast<char*>(iovec[0].iov_base));
iovec[0].iov_len = content_len;
std::copy(std::begin(content), std::end(content), static_cast<char*>(iovec[0].iov_base));
iovec[0].iov_len = std::size(content);
}
evbuffer_commit_space(out, iovec, 1);
}
return out;
}
static void add_time_header(struct evkeyvalq* headers, char const* key, time_t now)
@ -209,48 +211,32 @@ static void add_time_header(struct evkeyvalq* headers, char const* key, time_t n
evhttp_add_header(headers, key, fmt::format("{:%a %b %d %T %Y%n}", fmt::gmtime(now)).c_str());
}
static void evbuffer_ref_cleanup_tr_free(void const* /*data*/, size_t /*datalen*/, void* extra)
{
tr_free(extra);
}
static void serve_file(struct evhttp_request* req, tr_rpc_server* server, std::string_view filename)
{
if (req->type != EVHTTP_REQ_GET)
{
evhttp_add_header(req->output_headers, "Allow", "GET");
send_simple_response(req, 405, nullptr);
return;
}
else
auto content = std::vector<char>{};
tr_error* error = nullptr;
if (!tr_loadFile(filename, content, &error))
{
auto file_len = size_t{};
tr_error* error = nullptr;
void* const file = tr_loadFile(filename, &file_len, &error);
if (file == nullptr)
{
auto const tmp = fmt::format(FMT_STRING("{:s} ({:s})"), filename, error->message);
send_simple_response(req, HTTP_NOTFOUND, tmp.c_str());
tr_error_free(error);
}
else
{
auto const now = tr_time();
auto* const content = evbuffer_new();
evbuffer_add_reference(content, file, file_len, evbuffer_ref_cleanup_tr_free, file);
auto* const out = evbuffer_new();
evhttp_add_header(req->output_headers, "Content-Type", mimetype_guess(filename));
add_time_header(req->output_headers, "Date", now);
add_time_header(req->output_headers, "Expires", now + (24 * 60 * 60));
add_response(req, server, out, content);
evhttp_send_reply(req, HTTP_OK, "OK", out);
evbuffer_free(out);
evbuffer_free(content);
}
send_simple_response(req, HTTP_NOTFOUND, fmt::format("{} ({})", filename, error->message).c_str());
tr_error_free(error);
return;
}
auto const now = tr_time();
add_time_header(req->output_headers, "Date", now);
add_time_header(req->output_headers, "Expires", now + (24 * 60 * 60));
evhttp_add_header(req->output_headers, "Content-Type", mimetype_guess(filename));
auto* const response = make_response(req, server, std::string_view{ std::data(content), std::size(content) });
evhttp_send_reply(req, HTTP_OK, "OK", response);
evbuffer_free(response);
}
static void handle_web_client(struct evhttp_request* req, tr_rpc_server* server)
@ -298,18 +284,15 @@ struct rpc_response_data
tr_rpc_server* server;
};
static void rpc_response_func(tr_session* /*session*/, tr_variant* response, void* user_data)
static void rpc_response_func(tr_session* /*session*/, tr_variant* content, void* user_data)
{
auto* data = static_cast<struct rpc_response_data*>(user_data);
struct evbuffer* response_buf = tr_variantToBuf(response, TR_VARIANT_FMT_JSON_LEAN);
struct evbuffer* buf = evbuffer_new();
add_response(data->req, data->server, buf, response_buf);
auto* const response = make_response(data->req, data->server, tr_variantToStr(content, TR_VARIANT_FMT_JSON_LEAN));
evhttp_add_header(data->req->output_headers, "Content-Type", "application/json; charset=UTF-8");
evhttp_send_reply(data->req, HTTP_OK, "OK", buf);
evhttp_send_reply(data->req, HTTP_OK, "OK", response);
evbuffer_free(response);
evbuffer_free(buf);
evbuffer_free(response_buf);
tr_free(data);
}

View File

@ -142,70 +142,6 @@ void tr_timerAddMsec(struct event& timer, int msec)
***
**/
uint8_t* tr_loadFile(std::string_view path_in, size_t* size, tr_error** error)
{
auto const path = tr_pathbuf{ path_in };
/* try to stat the file */
auto info = tr_sys_path_info{};
tr_error* my_error = nullptr;
if (!tr_sys_path_get_info(path.c_str(), 0, &info, &my_error))
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
return nullptr;
}
if (info.type != TR_SYS_PATH_IS_FILE)
{
tr_logAddError(fmt::format(_("Couldn't read '{path}': Not a regular file"), fmt::arg("path", path)));
tr_error_set(error, TR_ERROR_EISDIR, "Not a regular file"sv);
return nullptr;
}
/* file size should be able to fit into size_t */
if constexpr (sizeof(info.size) > sizeof(*size))
{
TR_ASSERT(info.size <= SIZE_MAX);
}
/* Load the torrent file into our buffer */
auto const fd = tr_sys_file_open(path.c_str(), TR_SYS_FILE_READ | TR_SYS_FILE_SEQUENTIAL, 0, &my_error);
if (fd == TR_BAD_SYS_FILE)
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_error_propagate(error, &my_error);
return nullptr;
}
auto* buf = static_cast<uint8_t*>(tr_malloc(info.size + 1));
if (!tr_sys_file_read(fd, buf, info.size, nullptr, &my_error))
{
tr_logAddError(fmt::format(
_("Couldn't read '{path}': {error} ({error_code})"),
fmt::arg("path", path),
fmt::arg("error", my_error->message),
fmt::arg("error_code", my_error->code)));
tr_sys_file_close(fd);
tr_free(buf);
tr_error_propagate(error, &my_error);
return nullptr;
}
tr_sys_file_close(fd);
buf[info.size] = '\0';
*size = info.size;
return buf;
}
bool tr_loadFile(std::string_view path_in, std::vector<char>& setme, tr_error** error)
{
auto const path = tr_pathbuf{ path_in };

View File

@ -72,12 +72,6 @@ struct tr_error;
*/
[[nodiscard]] bool tr_wildmat(std::string_view text, std::string_view pattern);
/**
* @brief Loads a file and returns its contents.
* On failure, NULL is returned and errno is set.
*/
uint8_t* tr_loadFile(std::string_view filename, size_t* size, struct tr_error** error) TR_GNUC_MALLOC;
bool tr_loadFile(std::string_view filename, std::vector<char>& contents, tr_error** error = nullptr);
bool tr_saveFile(std::string_view filename, std::string_view contents, tr_error** error = nullptr);

View File

@ -87,26 +87,17 @@ protected:
return tor;
}
static bool testFileExistsAndConsistsOfThisString(tr_torrent const* tor, tr_file_index_t file_index, std::string const& str)
static bool testFileExistsAndConsistsOfThisString(tr_torrent const* tor, tr_file_index_t file_index, std::string_view str)
{
auto const str_len = str.size();
auto success = false;
auto* path = tr_torrentFindFile(tor, file_index);
if (path != nullptr)
if (auto const found = tor->findFile(file_index); found)
{
EXPECT_TRUE(tr_sys_path_exists(path));
size_t contents_len;
uint8_t* contents = tr_loadFile(path, &contents_len, nullptr);
success = contents != nullptr && str_len == contents_len && memcmp(contents, str.data(), contents_len) == 0;
tr_free(contents);
tr_free(path);
EXPECT_TRUE(tr_sys_path_exists(found->filename()));
auto contents = std::vector<char>{};
return tr_loadFile(found->filename(), contents) &&
std::string_view{ std::data(contents), std::size(contents) } == str;
}
return success;
return false;
}
static void expectHaveNone(tr_torrent* tor, uint64_t total_size)