Skip to content

Commit

Permalink
Add the ability to add torrents with base64 data URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
jesec committed Mar 6, 2021
1 parent a70d363 commit 36731c8
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 9 deletions.
4 changes: 3 additions & 1 deletion include/core/download_factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,11 @@ class DownloadFactory {
};

bool
is_network_uri(const std::string& uri);
is_data_uri(const std::string& uri);
bool
is_magnet_uri(const std::string& uri);
bool
is_network_uri(const std::string& uri);

}

Expand Down
16 changes: 11 additions & 5 deletions src/core/download_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@

namespace core {

bool
is_data_uri(const std::string& uri) {
return std::strncmp(uri.c_str(), "data:", 5) == 0 &&
uri.find("base64,", 5) != std::string::npos;
}

bool
is_magnet_uri(const std::string& uri) {
return std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
}

bool
is_network_uri(const std::string& uri) {
return std::strncmp(uri.c_str(), "http://", 7) == 0 ||
Expand All @@ -56,11 +67,6 @@ download_factory_add_stream(torrent::Object* root,
return true;
}

bool
is_magnet_uri(const std::string& uri) {
return std::strncmp(uri.c_str(), "magnet:?", 8) == 0;
}

DownloadFactory::DownloadFactory(Manager* m)
: m_manager(m) {

Expand Down
69 changes: 66 additions & 3 deletions src/core/manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,60 @@

namespace core {

constexpr static char padCharacter = '=';
static std::string
base64Decode(const std::string_view& input) {
if (input.length() % 4) // Sanity check
throw torrent::input_error("Invalid base64.");
size_t padding = 0;
if (input.length()) {
if (input[input.length() - 1] == padCharacter)
padding++;
if (input[input.length() - 2] == padCharacter)
padding++;
}
// Setup a vector to hold the result
std::string decodedBytes;
decodedBytes.reserve(((input.length() / 4) * 3) - padding);
long temp = 0; // Holds decoded quanta
std::string_view::const_iterator cursor = input.begin();
while (cursor < input.end()) {
for (size_t quantumPosition = 0; quantumPosition < 4; quantumPosition++) {
temp <<= 6;
if (*cursor >= 0x41 && *cursor <= 0x5A) // This area will need tweaking if
temp |= *cursor - 0x41; // you are using an alternate alphabet
else if (*cursor >= 0x61 && *cursor <= 0x7A)
temp |= *cursor - 0x47;
else if (*cursor >= 0x30 && *cursor <= 0x39)
temp |= *cursor + 0x04;
else if (*cursor == 0x2B)
temp |= 0x3E; // change to 0x2D for URL alphabet
else if (*cursor == 0x2F)
temp |= 0x3F; // change to 0x5F for URL alphabet
else if (*cursor == padCharacter) // pad
{
switch (input.end() - cursor) {
case 1: // One pad character
decodedBytes.push_back((temp >> 16) & 0x000000FF);
decodedBytes.push_back((temp >> 8) & 0x000000FF);
return decodedBytes;
case 2: // Two pad characters
decodedBytes.push_back((temp >> 10) & 0x000000FF);
return decodedBytes;
default:
throw torrent::input_error("Invalid padding in base64.");
}
} else
throw torrent::input_error("Invalid character in base64.");
cursor++;
}
decodedBytes.push_back((temp >> 16) & 0x000000FF);
decodedBytes.push_back((temp >> 8) & 0x000000FF);
decodedBytes.push_back((temp)&0x000000FF);
}
return decodedBytes;
}

void
Manager::push_log(const char* msg) {
m_log_important->lock_and_push_log(msg, strlen(msg), 0);
Expand Down Expand Up @@ -364,7 +418,7 @@ Manager::try_create_download(const std::string& uri,
const command_list_type& commands) {
// If the path was attempted loaded before, skip it.
if ((flags & create_tied) && !(flags & create_raw_data) &&
!is_network_uri(uri) && !is_magnet_uri(uri) &&
!is_network_uri(uri) && !is_magnet_uri(uri) && !is_data_uri(uri) &&
!file_status_cache()->insert(uri, flags & create_throw))
return;

Expand All @@ -379,10 +433,19 @@ Manager::try_create_download(const std::string& uri,
f->set_immediate(flags & create_throw);
f->slot_finished([f]() { delete f; });

if (flags & create_raw_data)
if (flags & create_raw_data) {
f->load_raw_data(uri);
else
} else if (is_data_uri(uri)) {
const unsigned long start = uri.find("base64,", 5) + 7;
if (start >= uri.size()) {
throw torrent::input_error("Empty base64.");
}

f->load_raw_data(base64Decode(std::string_view(uri.c_str() + start)));
f->variables()["tied_to_file"] = (int64_t)0;
} else {
f->load(uri);
}

f->commit();
}
Expand Down

0 comments on commit 36731c8

Please sign in to comment.