feat: add Chromecast playback support
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
namespace playback {
|
||||
inline bool validNetworkURL(const char *text) {
|
||||
if (!text) return false;
|
||||
const std::string_view url(text);
|
||||
if (url.size() > 65536) return false;
|
||||
const std::size_t start = url.starts_with("https://") ? 8 : url.starts_with("http://") ? 7 : 0;
|
||||
if (!start) return false;
|
||||
for (unsigned char value : url)
|
||||
if (value <= 32 || value == 127 || value == '\\') return false;
|
||||
const auto authority = url.substr(start, url.find_first_of("/?#", start) - start);
|
||||
if (authority.empty() || authority.find('@') != std::string_view::npos) return false;
|
||||
auto host = authority;
|
||||
std::string_view port;
|
||||
if (host.front() == '[') {
|
||||
const auto end = host.find(']');
|
||||
if (end == std::string_view::npos || end == 1) return false;
|
||||
if (end + 1 < host.size()) {
|
||||
if (host[end + 1] != ':') return false;
|
||||
port = host.substr(end + 2);
|
||||
if (port.empty()) return false;
|
||||
}
|
||||
host = host.substr(1, end - 1);
|
||||
std::array<char, INET6_ADDRSTRLEN> address{};
|
||||
if (host.size() >= address.size()) return false;
|
||||
std::memcpy(address.data(), host.data(), host.size());
|
||||
in6_addr parsed{};
|
||||
if (inet_pton(AF_INET6, address.data(), &parsed) != 1) return false;
|
||||
} else {
|
||||
const auto colon = host.find(':');
|
||||
if (colon != std::string_view::npos) {
|
||||
port = host.substr(colon + 1);
|
||||
host = host.substr(0, colon);
|
||||
if (port.empty()) return false;
|
||||
}
|
||||
if (host.empty()) return false;
|
||||
for (unsigned char value : host)
|
||||
if (!((value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z') ||
|
||||
(value >= '0' && value <= '9') || value == '.' || value == '-')) return false;
|
||||
}
|
||||
unsigned number = 0;
|
||||
for (unsigned char value : port) {
|
||||
if (value < '0' || value > '9') return false;
|
||||
number = number * 10 + value - '0';
|
||||
if (number > 65535) return false;
|
||||
}
|
||||
return port.empty() || number > 0;
|
||||
}
|
||||
inline bool validHeaders(const char *text) {
|
||||
if (!text) return true;
|
||||
const std::string_view headers(text);
|
||||
if (headers.size() > 65536) return false;
|
||||
std::size_t offset = 0;
|
||||
while (offset < headers.size()) {
|
||||
const auto end = headers.find("\r\n", offset);
|
||||
if (end == std::string_view::npos) return false;
|
||||
const auto line = headers.substr(offset, end - offset);
|
||||
const auto colon = line.find(':');
|
||||
if (colon == std::string_view::npos || colon == 0) return false;
|
||||
for (unsigned char value : line.substr(0, colon))
|
||||
if (!((value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z') ||
|
||||
(value >= '0' && value <= '9') ||
|
||||
std::string_view("!#$%&'*+-.^_`|~").find(value) != std::string_view::npos)) return false;
|
||||
for (unsigned char value : line.substr(colon + 1))
|
||||
if (value < 32 || value == 127) return false;
|
||||
offset = end + 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
inline std::string networkOrigin(const char *text) {
|
||||
if (!validNetworkURL(text)) return {};
|
||||
std::string_view url(text);
|
||||
const auto start = url.starts_with("https://") ? 8u : 7u;
|
||||
std::string authority(url.substr(start, url.find_first_of("/?#", start) - start));
|
||||
for (char &value : authority)
|
||||
if (value >= 'A' && value <= 'Z') value += 'a' - 'A';
|
||||
const auto colon = authority.front() == '[' ? authority.find(':', authority.find(']')) : authority.find(':');
|
||||
if (colon == std::string::npos) authority += start == 8 ? ":443" : ":80";
|
||||
else authority.replace(colon + 1, std::string::npos, std::to_string(std::stoul(authority.substr(colon + 1))));
|
||||
return std::string(url.substr(0, start)) + authority;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user