mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 05:39:22 +00:00
Compare commits
11 Commits
80ae6a4590
...
v0.16.24
| Author | SHA1 | Date | |
|---|---|---|---|
| 05cdd03cd2 | |||
| d1a6942ea7 | |||
| 3652329e2d | |||
| 7916e6022f | |||
| c59da0848e | |||
| e2f66ff08c | |||
| f0b6f2cb47 | |||
| d334b8d339 | |||
| 19b71a98b7 | |||
| 8ee3b984dd | |||
| 4e7129c71c |
+3
-3
@@ -1,6 +1,6 @@
|
||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||
|
||||
AC_INIT([rtorrent],[0.16.23],[sundell.software@gmail.com])
|
||||
AC_INIT([rtorrent],[0.16.24],[sundell.software@gmail.com])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_MACRO_DIRS([scripts])
|
||||
@@ -14,7 +14,7 @@ AX_CXX_COMPILE_STDCXX(20, noext, mandatory)
|
||||
|
||||
PKG_PROG_PKG_CONFIG
|
||||
|
||||
AC_DEFINE([API_VERSION], [27], [api version])
|
||||
AC_DEFINE([API_VERSION], [28], [api version])
|
||||
|
||||
RAK_CHECK_CFLAGS
|
||||
RAK_CHECK_CXXFLAGS
|
||||
@@ -49,7 +49,7 @@ fi
|
||||
|
||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||
PKG_CHECK_MODULES([ZLIB], [zlib])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.23])
|
||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.24])
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
TORRENT_WITH_XMLRPC_C
|
||||
|
||||
@@ -402,13 +402,21 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) {
|
||||
auto resultRaw = torrent::Object::create_list();
|
||||
auto& result = resultRaw.as_list();
|
||||
|
||||
for (const auto& connection : *download->connection_list()) {
|
||||
auto* connection_list = download->connection_list();
|
||||
const auto change_counter = connection_list->change_counter();
|
||||
|
||||
for (const auto& connection : *connection_list) {
|
||||
torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list();
|
||||
|
||||
for (auto cItr = ++args.begin(); cItr != args.end(); cItr++) {
|
||||
const std::string& cmd = cItr->as_string();
|
||||
|
||||
row.push_back(rpc::parse_command(rpc::make_target(connection), cmd.c_str(), cmd.c_str() + cmd.size()).first);
|
||||
|
||||
// Erasing a peer frees it and swaps the last element into its place, so
|
||||
// neither this peer nor the iteration survives a change to the list.
|
||||
if (connection_list->change_counter() != change_counter)
|
||||
throw torrent::input_error("Command changed the connection list during p.multicall.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -344,8 +344,8 @@ apply_ipv4_filter_dump() {
|
||||
torrent::Object raw_result = torrent::Object::create_list();
|
||||
torrent::Object::list_type& result = raw_result.as_list();
|
||||
|
||||
torrent::ipv4_table::range_map_type range_map = torrent::PeerList::ipv4_filter()->range_map;
|
||||
torrent::ipv4_table::range_map_type::iterator iter = range_map.begin();
|
||||
const torrent::ipv4_table::range_map_type& range_map = torrent::PeerList::ipv4_filter()->range_map;
|
||||
torrent::ipv4_table::range_map_type::const_iterator iter = range_map.begin();
|
||||
|
||||
while(iter != range_map.end()) {
|
||||
char buffer[64];
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
#include <torrent/throttle.h>
|
||||
#include <torrent/rate.h>
|
||||
#include <torrent/download/resource_manager.h>
|
||||
#include <torrent/net/socket_address.h>
|
||||
|
||||
#include "core/manager.h"
|
||||
#include "ui/root.h"
|
||||
@@ -16,59 +14,6 @@
|
||||
#include "control.h"
|
||||
#include "command_helpers.h"
|
||||
|
||||
std::pair<uint32_t, uint32_t>
|
||||
parse_address_range(const torrent::Object::list_type& args, torrent::Object::list_type::const_iterator itr) {
|
||||
unsigned int prefixWidth, ret;
|
||||
char dummy;
|
||||
char host[1024];
|
||||
torrent::sa_unique_ptr sa;
|
||||
|
||||
ret = std::sscanf(itr->as_string().c_str(), "%1023[^/]/%d%c", host, &prefixWidth, &dummy);
|
||||
|
||||
if (ret < 1)
|
||||
throw torrent::input_error("Invalid address/prefix.");
|
||||
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(host, AF_INET).get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
uint32_t begin, end;
|
||||
|
||||
auto sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
|
||||
|
||||
begin = end = sa_addr;
|
||||
|
||||
if (ret == 2) {
|
||||
if (++itr != args.end())
|
||||
throw torrent::input_error("Cannot specify both network and range end.");
|
||||
|
||||
uint32_t netmask = std::numeric_limits<uint32_t>::max() << (32 - prefixWidth);
|
||||
|
||||
if (prefixWidth >= 32 || sa_addr & ~netmask)
|
||||
throw torrent::input_error("Invalid address/prefix.");
|
||||
|
||||
end = sa_addr | ~netmask;
|
||||
|
||||
} else if (++itr != args.end()) {
|
||||
try {
|
||||
sa = torrent::sa_copy(torrent::sa_lookup_address(itr->as_string(), AF_INET).get());
|
||||
|
||||
} catch (torrent::input_error& e) {
|
||||
throw torrent::input_error("Could not resolve host: " + std::string(e.what()));
|
||||
}
|
||||
|
||||
sa_addr = htonl(reinterpret_cast<sockaddr_in*>(sa.get())->sin_addr.s_addr);
|
||||
end = sa_addr;
|
||||
}
|
||||
|
||||
// convert to [begin, end) making sure the end doesn't overflow
|
||||
// (this precludes 255.255.255.255 from ever matching, but that's not a real IP anyway)
|
||||
return std::make_pair((uint32_t)begin, (uint32_t)std::max(end, end + 1));
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
apply_throttle(const torrent::Object::list_type& args, bool up) {
|
||||
auto arg_itr = args.begin();
|
||||
|
||||
+12
-2
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
#include <regex>
|
||||
@@ -126,11 +127,20 @@ apply_value([[maybe_unused]] rpc::target_type target, const torrent::Object::lis
|
||||
if (args.front().is_value()) {
|
||||
val = args.front().as_value();
|
||||
} else {
|
||||
int base = args.size() > 1 ? args.back().is_value() ?
|
||||
args.back().as_value() : strtol(args.back().as_string().c_str(), NULL, 10) : 10;
|
||||
int64_t base = args.size() > 1 ? args.back().is_value() ?
|
||||
args.back().as_value() : strtoll(args.back().as_string().c_str(), NULL, 10) : 10;
|
||||
|
||||
if (base != 0 && (base < 2 || base > 36))
|
||||
throw torrent::input_error("'value' base must be 0 or between 2 and 36!");
|
||||
|
||||
char* endptr = 0;
|
||||
errno = 0;
|
||||
|
||||
val = strtoll(args.front().as_string().c_str(), &endptr, base);
|
||||
|
||||
if (errno == ERANGE)
|
||||
throw torrent::input_error("Number out of range: " + args.front().as_string());
|
||||
|
||||
while (*endptr == ' ' || *endptr == '\n') ++endptr;
|
||||
if (*endptr)
|
||||
throw torrent::input_error("Junk at end of number: " + args.front().as_string());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <torrent/exceptions.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/object_stream.h>
|
||||
#include <torrent/rate.h>
|
||||
@@ -62,7 +63,14 @@ DhtManager::load_dht_cache() {
|
||||
LT_LOG("could not open cache file (path:%s)", cache_filename.c_str());
|
||||
}
|
||||
|
||||
torrent::runtime::network_manager()->dht_controller()->initialize(cache);
|
||||
try {
|
||||
torrent::runtime::network_manager()->dht_controller()->initialize(cache);
|
||||
|
||||
} catch (const torrent::base_error& e) {
|
||||
LT_LOG_ERROR("cache file rejected, discarding (path:%s errmsg:%s)", cache_filename.c_str(), e.what());
|
||||
|
||||
torrent::runtime::network_manager()->dht_controller()->initialize(torrent::Object::create_map());
|
||||
}
|
||||
|
||||
if (m_start == dht_on)
|
||||
start_dht();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
#include <torrent/torrent.h>
|
||||
#include <torrent/system/callbacks.h>
|
||||
#include <torrent/system/thread.h>
|
||||
@@ -41,13 +43,20 @@ WindowLog::redraw() {
|
||||
|
||||
int pos = m_canvas->height();
|
||||
|
||||
for (iterator itr = m_log->end(), last = find_older(); itr != last && pos > 0; --pos) {
|
||||
itr--;
|
||||
std::vector<torrent::log_entry> entries;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
for (iterator itr = m_log->end(), last = find_older(); itr != last && entries.size() < static_cast<size_t>(pos); )
|
||||
entries.push_back(*--itr);
|
||||
}
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
char buffer[16];
|
||||
print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(itr->timestamp));
|
||||
print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(entry.timestamp));
|
||||
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.c_str());
|
||||
m_canvas->print(0, --pos, "(%s) %s", buffer, entry.message.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,8 +69,13 @@ WindowLog::receive_update() {
|
||||
if (!is_active())
|
||||
return;
|
||||
|
||||
auto itr = find_older();
|
||||
auto height = std::min(std::distance(itr, (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
std::iterator_traits<iterator>::difference_type height;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
height = std::min(std::distance(find_older(), (iterator)m_log->end()), (std::iterator_traits<iterator>::difference_type)10);
|
||||
}
|
||||
|
||||
if (height != m_max_height) {
|
||||
m_min_height = height != 0 ? 1 : 0;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include "canvas.h"
|
||||
#include "utils.h"
|
||||
@@ -29,24 +31,34 @@ WindowLogComplete::redraw() {
|
||||
|
||||
int pos = m_canvas->height();
|
||||
|
||||
for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && pos > 0; ) {
|
||||
itr--;
|
||||
std::vector<torrent::log_entry> entries;
|
||||
|
||||
{
|
||||
std::lock_guard<torrent::log_buffer> guard(*m_log);
|
||||
|
||||
for (iterator itr = m_log->end(), last = m_log->begin(); itr != last && entries.size() < static_cast<size_t>(pos); )
|
||||
entries.push_back(*--itr);
|
||||
}
|
||||
|
||||
for (const auto& entry : entries) {
|
||||
if (pos <= 0)
|
||||
break;
|
||||
|
||||
char buffer[16];
|
||||
|
||||
// Use an arbitrary min width of 60 for allowing multiple
|
||||
// lines. This should ensure we don't mess up the display when the
|
||||
// screen is shrunk too much.
|
||||
unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(itr->timestamp)) - buffer;
|
||||
unsigned int timeWidth = 3 + print_hhmmss_local(buffer, buffer + 16, static_cast<time_t>(entry.timestamp)) - buffer;
|
||||
|
||||
unsigned int logWidth = m_canvas->width() > 60 ? (m_canvas->width() - timeWidth) : (60 - timeWidth);
|
||||
unsigned int logHeight = (itr->message.size() + logWidth - 1) / logWidth;
|
||||
unsigned int logHeight = (entry.message.size() + logWidth - 1) / logWidth;
|
||||
|
||||
for (unsigned int j = logHeight; j > 0 && pos > 0; --j, --pos)
|
||||
if (j == 1)
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, itr->message.substr(0, m_canvas->width() - timeWidth).c_str());
|
||||
m_canvas->print(0, pos - 1, "(%s) %s", buffer, entry.message.substr(0, m_canvas->width() - timeWidth).c_str());
|
||||
else
|
||||
m_canvas->print(timeWidth, pos - 1, "%s", itr->message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str());
|
||||
m_canvas->print(timeWidth, pos - 1, "%s", entry.message.substr(logWidth * (j - 1), m_canvas->width() - timeWidth).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -550,8 +550,6 @@ handle_sigbus(int signum, siginfo_t* sa, [[maybe_unused]] void* ptr) {
|
||||
#else
|
||||
output << "Stack dump not enabled." << std::endl;
|
||||
#endif
|
||||
output << std::endl << "Error: " << std::strerror(sa->si_errno) << std::endl;
|
||||
|
||||
const char* signal_reason;
|
||||
|
||||
switch (sa->si_code) {
|
||||
|
||||
@@ -26,10 +26,7 @@ const size_t object_storage::key_size;
|
||||
|
||||
object_storage::iterator
|
||||
object_storage::find_raw_string(const torrent::raw_string& key) {
|
||||
fixed_key_type<64> k;
|
||||
k.set_c_str(key.data());
|
||||
|
||||
return find(k);
|
||||
return find(key_type::from_raw_string(key));
|
||||
}
|
||||
|
||||
object_storage::iterator
|
||||
|
||||
@@ -158,14 +158,7 @@ fixed_key_type<MaxSize>::set_data(const value_type* src_data, size_type src_size
|
||||
|
||||
template <size_t MaxSize> inline void
|
||||
fixed_key_type<MaxSize>::set_c_str(const value_type* src_data) {
|
||||
value_type* itr = m_data;
|
||||
const value_type* last = m_data + max_size;
|
||||
|
||||
while (itr != last && *src_data != '\0')
|
||||
*itr++ = *src_data++;
|
||||
|
||||
*itr = '\0';
|
||||
m_size = std::distance(m_data, itr);
|
||||
set_c_str(src_data, std::strlen(src_data));
|
||||
}
|
||||
|
||||
template <size_t MaxSize> inline void
|
||||
|
||||
@@ -172,6 +172,9 @@ RpcManager::set_size_limit(uint64_t size) {
|
||||
if (size > SCgiTask::max_content_size)
|
||||
throw torrent::input_error("XMLRPC size limit cannot exceed the SCGI content size limit.");
|
||||
|
||||
if (size < min_size_limit)
|
||||
throw torrent::input_error("XMLRPC size limit is too small to hold a request.");
|
||||
|
||||
m_xmlrpc.set_size_limit(size);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,10 @@ public:
|
||||
enum RPCType { XML,
|
||||
JSON };
|
||||
|
||||
// A limit below the shortest useful request rejects every request, the one
|
||||
// that would raise it again included.
|
||||
static constexpr uint64_t min_size_limit = 1024;
|
||||
|
||||
RpcManager() = default;
|
||||
~RpcManager() = default;
|
||||
|
||||
|
||||
+36
-8
@@ -30,6 +30,38 @@
|
||||
|
||||
namespace ui {
|
||||
|
||||
std::string
|
||||
create_filter_pattern(const std::string& input) {
|
||||
std::string pattern = input;
|
||||
|
||||
if (pattern.empty())
|
||||
return pattern;
|
||||
|
||||
if (pattern.back() != '$')
|
||||
pattern = pattern + ".*";
|
||||
if (pattern.front() != '^')
|
||||
pattern = ".*" + pattern;
|
||||
|
||||
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
create_filter_command(const std::string& pattern) {
|
||||
torrent::Object name = torrent::Object::create_dict_key();
|
||||
name.as_dict_key() = "d.name";
|
||||
|
||||
torrent::Object args = torrent::Object::create_list();
|
||||
args.as_list().push_back(name);
|
||||
args.as_list().push_back(torrent::Object(pattern));
|
||||
|
||||
torrent::Object command = torrent::Object::create_dict_key();
|
||||
command.as_dict_key() = "match";
|
||||
command.as_dict_obj() = args;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
DownloadList::DownloadList() {
|
||||
m_uiArray[DISPLAY_DOWNLOAD] = NULL;
|
||||
m_uiArray[DISPLAY_DOWNLOAD_LIST] = new ElementDownloadList();
|
||||
@@ -319,16 +351,12 @@ DownloadList::receive_exit_input(Input type) {
|
||||
current_view()->filter();
|
||||
current_view()->sort();
|
||||
} else {
|
||||
std::string pattern = input->str();
|
||||
if (pattern.back() != '$')
|
||||
pattern = pattern + ".*";
|
||||
if (pattern.front() != '^')
|
||||
pattern = ".*" + pattern;
|
||||
std::transform(pattern.begin(), pattern.end(), pattern.begin(), ::tolower);
|
||||
std::string temp_filter = "match={d.name=," + pattern + "}";
|
||||
std::string pattern = create_filter_pattern(input->str());
|
||||
|
||||
if (rpc::call_command_value("view.filter.temp.log"))
|
||||
control->core()->push_log_std("Temporary filter on '" + current_view()->name() + "' view: " + pattern);
|
||||
current_view()->set_filter_temp(temp_filter);
|
||||
|
||||
current_view()->set_filter_temp(create_filter_command(pattern));
|
||||
current_view()->filter();
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#ifndef RTORRENT_UI_DOWNLOAD_LIST_H
|
||||
#define RTORRENT_UI_DOWNLOAD_LIST_H
|
||||
|
||||
#include <string>
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "element_base.h"
|
||||
#include "globals.h"
|
||||
#include "display/manager.h"
|
||||
@@ -29,6 +32,12 @@ namespace ui {
|
||||
|
||||
class Download;
|
||||
|
||||
// Wrap a user-typed download name pattern in the anchors 'match' expects.
|
||||
std::string create_filter_pattern(const std::string& input);
|
||||
|
||||
// Build the 'match' command the temporary view filter runs against d.name.
|
||||
torrent::Object create_filter_command(const std::string& pattern);
|
||||
|
||||
class DownloadList : public ElementBase {
|
||||
public:
|
||||
typedef display::WindowDownloadList WList;
|
||||
|
||||
+5
-1
@@ -52,7 +52,9 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
|
||||
rpc/test_object_storage.cc \
|
||||
rpc/test_object_storage.h \
|
||||
rpc/test_parse_options.cc \
|
||||
rpc/test_parse_options.h
|
||||
rpc/test_parse_options.h \
|
||||
rpc/test_rpc_manager.cc \
|
||||
rpc/test_rpc_manager.h
|
||||
|
||||
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||
src/test_command_dynamic.cc \
|
||||
@@ -67,6 +69,8 @@ rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||
src/test_command_string.h \
|
||||
src/test_setup.cc \
|
||||
src/test_setup.h \
|
||||
src/test_ui_download_list.cc \
|
||||
src/test_ui_download_list.h \
|
||||
src/test_watch_ready_queue.cc \
|
||||
src/test_watch_ready_queue.h
|
||||
|
||||
|
||||
@@ -59,6 +59,23 @@ TestObjectStorage::test_validate_keys() {
|
||||
// The over-long key must not have been stored as the empty key.
|
||||
CPPUNIT_ASSERT(m_storage.find_raw_string(torrent::raw_string::from_c_str("")) == m_storage.end());
|
||||
|
||||
// An over-long key must not be truncated into a match either.
|
||||
CPPUNIT_ASSERT(m_storage.find_raw_string(torrent::raw_string::from_string(key_max + 'k')) == m_storage.end());
|
||||
|
||||
// set_c_str puts the terminating nul at m_data[size()], so size() has to
|
||||
// stay below max_size for that write to land inside the array.
|
||||
rpc::object_storage::key_type key_long;
|
||||
key_long.set_c_str(std::string(rpc::object_storage::key_size + 1, 'k').c_str());
|
||||
|
||||
CPPUNIT_ASSERT(key_long.size() < rpc::object_storage::key_size);
|
||||
|
||||
m_storage.clear();
|
||||
m_storage.insert_str("test_5", torrent::Object("a"), rpc::object_storage::flag_string_type);
|
||||
|
||||
// insert rejects a key holding a nul-char, so a lookup must not match past one.
|
||||
CPPUNIT_ASSERT(m_storage.find_raw_string(torrent::raw_string("test_5\0x", 8)) == m_storage.end());
|
||||
CPPUNIT_ASSERT(m_storage.find_raw_string(torrent::raw_string::from_c_str("test_5")) != m_storage.end());
|
||||
|
||||
m_storage.clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/rpc/test_rpc_manager.h"
|
||||
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rpc/scgi_task.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestRpcManager);
|
||||
|
||||
// A size limit too small to hold any request rejects every request, including
|
||||
// the one that would put it back, so it can only be undone by a restart.
|
||||
void
|
||||
TestRpcManager::test_size_limit_bounds() {
|
||||
CPPUNIT_ASSERT_THROW(m_rpc_manager.set_size_limit(0), torrent::input_error);
|
||||
CPPUNIT_ASSERT_THROW(m_rpc_manager.set_size_limit(rpc::RpcManager::min_size_limit - 1), torrent::input_error);
|
||||
CPPUNIT_ASSERT_THROW(m_rpc_manager.set_size_limit(rpc::SCgiTask::max_content_size + 1), torrent::input_error);
|
||||
|
||||
CPPUNIT_ASSERT_NO_THROW(m_rpc_manager.set_size_limit(rpc::RpcManager::min_size_limit));
|
||||
CPPUNIT_ASSERT_NO_THROW(m_rpc_manager.set_size_limit(rpc::SCgiTask::max_content_size));
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
#include "rpc/rpc_manager.h"
|
||||
|
||||
class TestRpcManager : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestRpcManager);
|
||||
|
||||
CPPUNIT_TEST(test_size_limit_bounds);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void test_size_limit_bounds();
|
||||
|
||||
private:
|
||||
rpc::RpcManager m_rpc_manager;
|
||||
};
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include "test/src/test_command_dynamic.h"
|
||||
|
||||
#include "helpers/assert.h"
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
@@ -82,3 +84,30 @@ TestCommandDynamic::test_insert_list() {
|
||||
CPPUNIT_ASSERT(filled.is_list());
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, filled.as_list().size());
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandDynamic::test_value_base() {
|
||||
auto value = [](std::initializer_list<torrent::Object> objects) {
|
||||
auto args = torrent::Object::create_list();
|
||||
|
||||
for (const auto& object : objects)
|
||||
args.as_list().push_back(object);
|
||||
|
||||
return rpc::commands.call_command("value", args).as_value();
|
||||
};
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t(10), value({"10"}));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t(255), value({"ff", int64_t(16)}));
|
||||
|
||||
// strtoll only defines base 0 and base 2 through 36.
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"10", int64_t(1)}); } );
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"10", int64_t(37)}); } );
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"10", int64_t(-1)}); } );
|
||||
|
||||
// An out-of-range base must not be narrowed into a valid one.
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"10", int64_t(1) << 40}); } );
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"ff", (int64_t(1) << 32) + 16}); } );
|
||||
|
||||
// A number too large for the result must be rejected, not clamped.
|
||||
ASSERT_CATCH_INPUT_ERROR( { value({"99999999999999999999999"}); } );
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ class TestCommandDynamic : public test_fixture {
|
||||
CPPUNIT_TEST(test_get_set);
|
||||
CPPUNIT_TEST(test_old_style);
|
||||
CPPUNIT_TEST(test_insert_list);
|
||||
CPPUNIT_TEST(test_value_base);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
@@ -20,6 +21,7 @@ public:
|
||||
|
||||
void test_old_style();
|
||||
void test_insert_list();
|
||||
void test_value_base();
|
||||
|
||||
private:
|
||||
std::unique_ptr<TestMainThread> m_test_main_thread;
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/src/test_ui_download_list.h"
|
||||
|
||||
#include "ui/download_list.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestUiDownloadList);
|
||||
|
||||
void
|
||||
TestUiDownloadList::test_filter_pattern() {
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(""), ui::create_filter_pattern(""));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".*linux.*"), ui::create_filter_pattern("linux"));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("^linux.*"), ui::create_filter_pattern("^linux"));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".*linux$"), ui::create_filter_pattern("linux$"));
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".*linux.*"), ui::create_filter_pattern("LiNuX"));
|
||||
}
|
||||
|
||||
void
|
||||
TestUiDownloadList::test_filter_command() {
|
||||
torrent::Object command = ui::create_filter_command(".*linux.*");
|
||||
|
||||
CPPUNIT_ASSERT(command.is_dict_key());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("match"), command.as_dict_key());
|
||||
|
||||
const torrent::Object::list_type& args = command.as_dict_obj().as_list();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, args.size());
|
||||
CPPUNIT_ASSERT(args.front().is_dict_key());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("d.name"), args.front().as_dict_key());
|
||||
CPPUNIT_ASSERT(args.back().is_string());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".*linux.*"), args.back().as_string());
|
||||
}
|
||||
|
||||
// A pattern that closes the 'match' argument early and appends a second
|
||||
// command must stay a single inert string argument.
|
||||
void
|
||||
TestUiDownloadList::test_filter_command_does_not_inject() {
|
||||
const std::string pattern = ui::create_filter_pattern("zzz},$d.custom1.set={pwned");
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(std::string(".*zzz},$d.custom1.set={pwned.*"), pattern);
|
||||
|
||||
torrent::Object command = ui::create_filter_command(pattern);
|
||||
|
||||
CPPUNIT_ASSERT(command.is_dict_key());
|
||||
CPPUNIT_ASSERT_EQUAL(std::string("match"), command.as_dict_key());
|
||||
|
||||
const torrent::Object::list_type& args = command.as_dict_obj().as_list();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL((size_t)2, args.size());
|
||||
CPPUNIT_ASSERT(args.back().is_string());
|
||||
CPPUNIT_ASSERT_EQUAL(pattern, args.back().as_string());
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestUiDownloadList : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestUiDownloadList);
|
||||
|
||||
CPPUNIT_TEST(test_filter_pattern);
|
||||
CPPUNIT_TEST(test_filter_command);
|
||||
CPPUNIT_TEST(test_filter_command_does_not_inject);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void test_filter_pattern();
|
||||
void test_filter_command();
|
||||
void test_filter_command_does_not_inject();
|
||||
};
|
||||
Reference in New Issue
Block a user