fix web_seed redirects (#1651)
fix web_seed redirects, make all redirects ephemeral (to avoid resume serialization). remove dup slash for redirects in proxy mode. consolidate {convert_path_to_posix,escape_path} to escape_file_path
This commit is contained in:
parent
7204082088
commit
7a8ffc2f2d
|
@ -1 +1 @@
|
|||
Subproject commit 36b46fc2c316d34714315c04c87cf74de6efae90
|
||||
Subproject commit 60d786b8fa6ddaacdc98bdf691220660bc194494
|
|
@ -36,11 +36,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent_info.hpp"
|
||||
#include "libtorrent/alert_types.hpp"
|
||||
#include "simulator/http_server.hpp"
|
||||
#include "simulator/http_proxy.hpp"
|
||||
#include "settings.hpp"
|
||||
#include "libtorrent/create_torrent.hpp"
|
||||
#include "simulator/simulator.hpp"
|
||||
#include "setup_swarm.hpp"
|
||||
#include "utils.hpp"
|
||||
#include "make_proxy_settings.hpp"
|
||||
#include "simulator/utils.hpp"
|
||||
#include <iostream>
|
||||
|
||||
|
@ -49,9 +51,10 @@ using namespace libtorrent;
|
|||
|
||||
namespace lt = libtorrent;
|
||||
|
||||
int const piece_size = 0x4000;
|
||||
|
||||
add_torrent_params create_torrent(file_storage& fs, bool const pad_files = false)
|
||||
{
|
||||
int const piece_size = 0x4000;
|
||||
libtorrent::create_torrent t(fs, piece_size
|
||||
, pad_files ? piece_size : -1
|
||||
, pad_files ? create_torrent::optimize_alignment : 0);
|
||||
|
@ -221,7 +224,7 @@ std::string generate_content(lt::file_storage const& fs, file_index_t file
|
|||
, std::int64_t offset, std::int64_t len)
|
||||
{
|
||||
std::string ret;
|
||||
ret.reserve(len);
|
||||
ret.reserve(lt::aux::numeric_cast<std::size_t>(len));
|
||||
std::int64_t const file_offset = fs.file_offset(file);
|
||||
int const piece_size = fs.piece_length();
|
||||
for (std::int64_t i = offset + file_offset; i < offset + file_offset + len; ++i)
|
||||
|
@ -383,6 +386,68 @@ TORRENT_TEST(multi_file_redirect)
|
|||
TEST_EQUAL(seeding, true);
|
||||
}
|
||||
|
||||
// test web_seed redirect through proxy
|
||||
TORRENT_TEST(multi_file_redirect_through_proxy)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
file_storage fs;
|
||||
fs.add_file(combine_path("foo", "1"), 0xc000);
|
||||
fs.add_file(combine_path("foo", "2"), 0xc030);
|
||||
lt::add_torrent_params params = ::create_torrent(fs);
|
||||
params.url_seeds.push_back("http://2.2.2.2:8080/");
|
||||
|
||||
bool seeding = false;
|
||||
|
||||
run_test(
|
||||
[¶ms](lt::session& ses)
|
||||
{
|
||||
settings_pack pack;
|
||||
|
||||
pack.set_int(settings_pack::proxy_type, settings_pack::http);
|
||||
pack.set_str(settings_pack::proxy_hostname, "50.50.50.50");
|
||||
pack.set_str(settings_pack::proxy_username, "testuser");
|
||||
pack.set_str(settings_pack::proxy_password, "testpass");
|
||||
pack.set_int(settings_pack::proxy_port, 4445);
|
||||
pack.set_bool(settings_pack::proxy_hostnames, true);
|
||||
ses.apply_settings(pack);
|
||||
|
||||
ses.async_add_torrent(params);
|
||||
},
|
||||
[&](lt::session& ses, lt::alert const* alert) {
|
||||
if (lt::alert_cast<lt::torrent_finished_alert>(alert)) {
|
||||
seeding = true;
|
||||
}
|
||||
},
|
||||
[&fs](sim::simulation& sim, lt::session& ses)
|
||||
{
|
||||
sim::asio::io_service proxy_ios(sim, address_v4::from_string("50.50.50.50"));
|
||||
sim::http_proxy http_p(proxy_ios, 4445);
|
||||
|
||||
// http1 is the root web server that will just redirect requests to
|
||||
// other servers
|
||||
sim::asio::io_service web_server1(sim, address_v4::from_string("2.2.2.2"));
|
||||
sim::http_server http1(web_server1, 8080);
|
||||
// redirect file 1 and file 2 to different servers
|
||||
http1.register_redirect("/foo/1", "http://3.3.3.3:4444/bla/file1");
|
||||
http1.register_redirect("/foo/2", "http://4.4.4.4:9999/bar/file2");
|
||||
|
||||
// server for file 1
|
||||
sim::asio::io_service web_server2(sim, address_v4::from_string("3.3.3.3"));
|
||||
sim::http_server http2(web_server2, 4444);
|
||||
serve_content_for(http2, "/bla/file1", fs, file_index_t(0));
|
||||
|
||||
// server for file 2
|
||||
sim::asio::io_service web_server3(sim, address_v4::from_string("4.4.4.4"));
|
||||
sim::http_server http3(web_server3, 9999);
|
||||
serve_content_for(http3, "/bar/file2", fs, file_index_t(1));
|
||||
|
||||
sim.run();
|
||||
}
|
||||
);
|
||||
|
||||
TEST_EQUAL(seeding, true);
|
||||
}
|
||||
|
||||
// this is expected to fail, since the files are not aligned and redirected to
|
||||
// separate servers, without pad files
|
||||
TORRENT_TEST(multi_file_unaligned_redirect)
|
||||
|
|
|
@ -57,6 +57,8 @@ namespace libtorrent
|
|||
{
|
||||
constexpr int request_size_overhead = 5000;
|
||||
|
||||
std::string escape_file_path(file_storage const& storage, file_index_t index);
|
||||
|
||||
web_peer_connection::web_peer_connection(peer_connection_args const& pack
|
||||
, web_seed_t& web)
|
||||
: web_connection_base(pack, web)
|
||||
|
@ -107,11 +109,7 @@ web_peer_connection::web_peer_connection(peer_connection_args const& pack
|
|||
|
||||
if (!m_url.empty() && m_url[m_url.size() - 1] == '/')
|
||||
{
|
||||
std::string tmp = t->torrent_file().files().file_path(file_index_t(0));
|
||||
#ifdef TORRENT_WINDOWS
|
||||
convert_path_to_posix(tmp);
|
||||
#endif
|
||||
m_url += escape_path(tmp);
|
||||
m_url += escape_file_path(t->torrent_file().files(), file_index_t(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,6 +124,15 @@ web_peer_connection::web_peer_connection(peer_connection_args const& pack
|
|||
#endif
|
||||
}
|
||||
|
||||
std::string escape_file_path(file_storage const& storage, file_index_t index)
|
||||
{
|
||||
std::string new_path { storage.file_path(index) };
|
||||
#ifdef TORRENT_WINDOWS
|
||||
convert_path_to_posix(new_path);
|
||||
#endif
|
||||
return escape_path(new_path);
|
||||
}
|
||||
|
||||
void web_peer_connection::on_connected()
|
||||
{
|
||||
if (m_web->have_files.empty())
|
||||
|
@ -380,11 +387,8 @@ void web_peer_connection::write_request(peer_request const& r)
|
|||
std::vector<file_slice> files = info.orig_files().map_block(req.piece, req.start
|
||||
, req.length);
|
||||
|
||||
for (std::vector<file_slice>::iterator i = files.begin();
|
||||
i != files.end(); ++i)
|
||||
for (auto const &f : files)
|
||||
{
|
||||
file_slice const& f = *i;
|
||||
|
||||
file_request_t file_req;
|
||||
file_req.file_index = f.file_index;
|
||||
file_req.start = f.offset;
|
||||
|
@ -411,7 +415,10 @@ void web_peer_connection::write_request(peer_request const& r)
|
|||
auto redirection = m_web->redirects.find(f.file_index);
|
||||
if (redirection != m_web->redirects.end())
|
||||
{
|
||||
request += redirection->second;
|
||||
auto const& redirect = redirection->second;
|
||||
// in case of http proxy "request" already contains m_url with trailing slash, so let's skip dup slash
|
||||
bool const trailing_slash = using_proxy && !redirect.empty() && redirect[0] == '/';
|
||||
request.append(redirect, trailing_slash, std::string::npos);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -422,11 +429,7 @@ void web_peer_connection::write_request(peer_request const& r)
|
|||
request += m_path;
|
||||
}
|
||||
|
||||
std::string path = info.orig_files().file_path(f.file_index);
|
||||
#ifdef TORRENT_WINDOWS
|
||||
convert_path_to_posix(path);
|
||||
#endif
|
||||
request += escape_path(path);
|
||||
request += escape_file_path(info.orig_files(), f.file_index);
|
||||
}
|
||||
request += " HTTP/1.1\r\n";
|
||||
add_headers(request, m_settings, using_proxy);
|
||||
|
@ -640,7 +643,15 @@ void web_peer_connection::handle_redirect(int const bytes_left)
|
|||
|
||||
// add_web_seed won't add duplicates. If we have already added an entry
|
||||
// with this URL, we'll get back the existing entry
|
||||
web_seed_t* web = t->add_web_seed(redirect_base, web_seed_entry::url_seed, m_external_auth, m_extra_headers);
|
||||
|
||||
// "ephemeral" flag should be set to avoid "web_seed_t" saving in resume data.
|
||||
// E.g. original "web_seed_t" request url points to "http://example1.com/file1" and
|
||||
// web server responses with redirect location "http://example2.com/subpath/file2".
|
||||
// "handle_redirect" process this location to create new "web_seed_t"
|
||||
// with base url=="http://example2.com/" and redirects[0]=="/subpath/file2").
|
||||
// If we try to load resume with such "web_seed_t" then "web_peer_connection" will send
|
||||
// request with wrong path "http://example2.com/file1" (cause "redirects" map is not serialized in resume)
|
||||
web_seed_t* web = t->add_web_seed(redirect_base, web_seed_entry::url_seed, m_external_auth, m_extra_headers, true);
|
||||
web->have_files.resize(t->torrent_file().num_files(), false);
|
||||
|
||||
// the new web seed we're adding only has this file for now
|
||||
|
@ -649,6 +660,7 @@ void web_peer_connection::handle_redirect(int const bytes_left)
|
|||
if (web->have_files.get_bit(file_index) == false)
|
||||
{
|
||||
web->have_files.set_bit(file_index);
|
||||
|
||||
if (web->peer_info.connection != nullptr)
|
||||
{
|
||||
peer_connection* pc = static_cast<peer_connection*>(web->peer_info.connection);
|
||||
|
@ -677,7 +689,7 @@ void web_peer_connection::handle_redirect(int const bytes_left)
|
|||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
peer_log(peer_log_alert::info, "LOCATION", "%s", location.c_str());
|
||||
#endif
|
||||
t->add_web_seed(location, web_seed_entry::url_seed, m_external_auth, m_extra_headers);
|
||||
t->add_web_seed(location, web_seed_entry::url_seed, m_external_auth, m_extra_headers, true);
|
||||
|
||||
// this web seed doesn't have any files. Don't try to request from it
|
||||
// again this session
|
||||
|
@ -780,9 +792,8 @@ void web_peer_connection::on_receive(error_code const& error
|
|||
peer_log(peer_log_alert::info, "STATUS"
|
||||
, "%d %s", m_parser.status_code(), m_parser.message().c_str());
|
||||
std::multimap<std::string, std::string> const& headers = m_parser.headers();
|
||||
for (std::multimap<std::string, std::string>::const_iterator i = headers.begin()
|
||||
, end(headers.end()); i != end; ++i)
|
||||
peer_log(peer_log_alert::info, "STATUS", " %s: %s", i->first.c_str(), i->second.c_str());
|
||||
for (auto const &i : headers)
|
||||
peer_log(peer_log_alert::info, "STATUS", " %s: %s", i.first.c_str(), i.second.c_str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -225,16 +225,16 @@ void change_directory(std::string const& f, error_code& ec)
|
|||
#ifdef TORRENT_WINDOWS
|
||||
#if TORRENT_USE_WSTRING
|
||||
#define SetCurrentDirectory_ SetCurrentDirectoryW
|
||||
std::wstring n = convert_to_wstring(f);
|
||||
native_path_string const n = convert_to_wstring(f);
|
||||
#else
|
||||
#define SetCurrentDirectory_ SetCurrentDirectoryA
|
||||
std::string const& n = convert_to_native(f);
|
||||
native_path_string const n = convert_to_native(f);
|
||||
#endif // TORRENT_USE_WSTRING
|
||||
|
||||
if (SetCurrentDirectory_(n.c_str()) == 0)
|
||||
ec.assign(GetLastError(), system_category());
|
||||
#undef SetCurrentDirectory_
|
||||
#else
|
||||
std::string n = convert_to_native(f);
|
||||
native_path_string const n = convert_to_native_path_string(f);
|
||||
int ret = ::chdir(n.c_str());
|
||||
if (ret != 0)
|
||||
ec.assign(errno, system_category());
|
||||
|
@ -361,10 +361,8 @@ EXPORT int main(int argc, char const* argv[])
|
|||
#else
|
||||
process_id = getpid();
|
||||
#endif
|
||||
std::string root_dir = current_working_directory();
|
||||
char dir[40];
|
||||
snprintf(dir, sizeof(dir), "test_tmp_%u", process_id);
|
||||
std::string unit_dir_prefix = combine_path(root_dir, dir);
|
||||
std::string const root_dir = current_working_directory();
|
||||
std::string const unit_dir_prefix = combine_path(root_dir, "test_tmp_" + std::to_string(process_id) + "_");
|
||||
std::printf("test: %s\ncwd_prefix = \"%s\"\nrnd = %x\n"
|
||||
, executable, unit_dir_prefix.c_str(), libtorrent::random(0xffffffff));
|
||||
|
||||
|
@ -383,10 +381,7 @@ EXPORT int main(int argc, char const* argv[])
|
|||
if (filter && tests_to_run.count(_g_unit_tests[i].name) == 0)
|
||||
continue;
|
||||
|
||||
std::string unit_dir = unit_dir_prefix;
|
||||
char i_str[40];
|
||||
snprintf(i_str, sizeof(i_str), "%u", i);
|
||||
unit_dir.append(i_str);
|
||||
std::string const unit_dir = unit_dir_prefix + std::to_string(i);
|
||||
error_code ec;
|
||||
create_directory(unit_dir, ec);
|
||||
if (ec)
|
||||
|
|
Loading…
Reference in New Issue