diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index d55577f77..f74b3b2ee 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -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(iovec[0].iov_base)); - iovec[0].iov_len = content_len; + std::copy(std::begin(content), std::end(content), static_cast(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{}; + 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(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); } diff --git a/libtransmission/utils.cc b/libtransmission/utils.cc index be35c7395..dd4114b8f 100644 --- a/libtransmission/utils.cc +++ b/libtransmission/utils.cc @@ -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(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& setme, tr_error** error) { auto const path = tr_pathbuf{ path_in }; diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 6acdbb2a8..0eb653fbe 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -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& contents, tr_error** error = nullptr); bool tr_saveFile(std::string_view filename, std::string_view contents, tr_error** error = nullptr); diff --git a/tests/libtransmission/rename-test.cc b/tests/libtransmission/rename-test.cc index fe3cc685a..b6ba086e1 100644 --- a/tests/libtransmission/rename-test.cc +++ b/tests/libtransmission/rename-test.cc @@ -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{}; + 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)