mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 05:39:22 +00:00
Answer an oversized RPC response with a fault
Cap XML-RPC and JSON-RPC output at the SCGI response limit before handing it over.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
#include "rpc/command_map.h"
|
||||
#include "rpc/nlohmann/json.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/scgi_task.h"
|
||||
#include "torrent/exceptions.h"
|
||||
#include "torrent/object.h"
|
||||
#include "utils/functional.h"
|
||||
@@ -264,6 +265,13 @@ JsonRpc::process(const char* in_buffer, uint32_t length, slot_write callback) {
|
||||
|
||||
std::string response_str = response.dump();
|
||||
|
||||
if (response_str.size() > SCgiTask::max_response_size) {
|
||||
const auto& id = response.is_object() && response.contains("id") ? response["id"] : json(nullptr);
|
||||
auto err_str = json_error(JSONRPC_INTERNAL_ERROR, "response size exceeds maximum RPC limit", id).dump();
|
||||
|
||||
return callback(err_str.c_str(), err_str.size());
|
||||
}
|
||||
|
||||
return callback(response_str.c_str(), response_str.size());
|
||||
|
||||
} catch (json::exception& e) {
|
||||
|
||||
@@ -405,7 +405,7 @@ void
|
||||
SCgiTask::receive_write(const char* buffer, uint32_t length) {
|
||||
assert(torrent::this_thread::thread() == torrent::main_thread::thread());
|
||||
|
||||
if (buffer == nullptr || length > (100 << 20))
|
||||
if (buffer == nullptr || length > max_response_size)
|
||||
throw torrent::internal_error("SCgiTask::receive_write(...) received bad input.");
|
||||
|
||||
// Main thread callback already locked this mutex.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define RTORRENT_RPC_SCGI_TASK_H
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
@@ -18,6 +19,8 @@ public:
|
||||
static constexpr int max_header_size = 2000;
|
||||
static constexpr int max_content_size = (1 << 26);
|
||||
|
||||
static constexpr uint32_t max_response_size = (100 << 20);
|
||||
|
||||
static constexpr auto timeout_request = std::chrono::seconds(60);
|
||||
|
||||
enum ContentType { XML, JSON };
|
||||
|
||||
@@ -425,6 +425,14 @@ XmlRpc::process(const char* inBuffer, uint32_t length, slot_write slotWrite) {
|
||||
// remains.
|
||||
tinyxml2::XMLPrinter printer(nullptr, true, 0);
|
||||
process_document(&doc, &printer);
|
||||
|
||||
if (printer.CStrSize() - 1 > static_cast<int>(SCgiTask::max_response_size)) {
|
||||
tinyxml2::XMLPrinter fault_printer(nullptr, true, 0);
|
||||
print_xmlrpc_fault(XMLRPC_LIMIT_EXCEEDED_ERROR, "Response size exceeds maximum XML-RPC limit", &fault_printer);
|
||||
|
||||
return slotWrite(fault_printer.CStr(), fault_printer.CStrSize() - 1);
|
||||
}
|
||||
|
||||
return slotWrite(printer.CStr(), printer.CStrSize() - 1);
|
||||
} catch (rpc_error& e) {
|
||||
tinyxml2::XMLPrinter printer(nullptr, true, 0);
|
||||
|
||||
Reference in New Issue
Block a user