diff --git a/CMakeLists.txt b/CMakeLists.txt index d184ca1b..eb70f6c1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -94,7 +94,7 @@ add_definitions(-g -funsigned-char -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D set(libHeaders ${SOURCE_DIR}/lib/amf.h ${SOURCE_DIR}/lib/auth.h - ${SOURCE_DIR}/lib/base64.h + ${SOURCE_DIR}/lib/encode.h ${SOURCE_DIR}/lib/bitfields.h ${SOURCE_DIR}/lib/bitstream.h ${SOURCE_DIR}/lib/checksum.h @@ -128,7 +128,7 @@ set(libHeaders set(libSources ${SOURCE_DIR}/lib/amf.cpp ${SOURCE_DIR}/lib/auth.cpp - ${SOURCE_DIR}/lib/base64.cpp + ${SOURCE_DIR}/lib/encode.cpp ${SOURCE_DIR}/lib/bitfields.cpp ${SOURCE_DIR}/lib/bitstream.cpp ${SOURCE_DIR}/lib/config.cpp diff --git a/lib/base64.cpp b/lib/base64.cpp deleted file mode 100644 index 7048616c..00000000 --- a/lib/base64.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "base64.h" - -/// Needed for base64_encode function -const std::string Base64::chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -/// Helper for base64_decode function -inline bool Base64::is_base64(unsigned char c) { - return (isalnum(c) || (c == '+') || (c == '/')); -} - -/// Used to base64 encode data. Input is the plaintext as std::string, output is the encoded data as std::string. -/// \param input Plaintext data to encode. -/// \returns Base64 encoded data. -std::string Base64::encode(std::string const input) { - std::string ret; - unsigned int in_len = input.size(); - char quad[4], triple[3]; - unsigned int i, x, n = 3; - for (x = 0; x < in_len; x = x + 3) { - if ((in_len - x) / 3 == 0) { - n = (in_len - x) % 3; - } - for (i = 0; i < 3; i++) { - triple[i] = '0'; - } - for (i = 0; i < n; i++) { - triple[i] = input[x + i]; - } - quad[0] = chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100 - quad[1] = chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11 - quad[2] = chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110 - quad[3] = chars[triple[2] & 0x3F]; // 3F = 111111 - if (n < 3) { - quad[3] = '='; - } - if (n < 2) { - quad[2] = '='; - } - for (i = 0; i < 4; i++) { - ret += quad[i]; - } - } - return ret; -} //base64_encode - -/// Used to base64 decode data. Input is the encoded data as std::string, output is the plaintext data as std::string. -/// \param encoded_string Base64 encoded data to decode. -/// \returns Plaintext decoded data. -std::string Base64::decode(std::string const & encoded_string) { - int in_len = encoded_string.size(); - int i = 0; - int j = 0; - int in_ = 0; - unsigned char char_array_4[4], char_array_3[3]; - std::string ret; - while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { - char_array_4[i++ ] = encoded_string[in_]; - in_++; - if (i == 4) { - for (i = 0; i < 4; i++) { - char_array_4[i] = chars.find(char_array_4[i]); - } - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (i = 0; (i < 3); i++) { - ret += char_array_3[i]; - } - i = 0; - } - } - if (i) { - for (j = i; j < 4; j++) { - char_array_4[j] = 0; - } - for (j = 0; j < 4; j++) { - char_array_4[j] = chars.find(char_array_4[j]); - } - char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); - char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); - char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; - for (j = 0; (j < i - 1); j++) - ret += char_array_3[j]; - } - return ret; -} diff --git a/lib/base64.h b/lib/base64.h deleted file mode 100644 index 684c4ba1..00000000 --- a/lib/base64.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -/// Holds base64 decoding and encoding functions. -class Base64 { - private: - static const std::string chars; - static inline bool is_base64(unsigned char c); - public: - static std::string encode(std::string const input); - static std::string decode(std::string const & encoded_string); -}; diff --git a/lib/encode.cpp b/lib/encode.cpp new file mode 100644 index 00000000..32bd8da6 --- /dev/null +++ b/lib/encode.cpp @@ -0,0 +1,148 @@ +#include "encode.h" + +namespace Encodings { + + /// Needed for base64_encode function + const std::string Base64::chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /// Helper for base64_decode function + inline bool Base64::is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); + } + + /// Used to base64 encode data. Input is the plaintext as std::string, output is the encoded data as std::string. + /// \param input Plaintext data to encode. + /// \returns Base64 encoded data. + std::string Base64::encode(std::string const input) { + std::string ret; + unsigned int in_len = input.size(); + char quad[4], triple[3]; + unsigned int i, x, n = 3; + for (x = 0; x < in_len; x = x + 3) { + if ((in_len - x) / 3 == 0) { + n = (in_len - x) % 3; + } + for (i = 0; i < 3; i++) { + triple[i] = '0'; + } + for (i = 0; i < n; i++) { + triple[i] = input[x + i]; + } + quad[0] = chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100 + quad[1] = chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11 + quad[2] = chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110 + quad[3] = chars[triple[2] & 0x3F]; // 3F = 111111 + if (n < 3) { + quad[3] = '='; + } + if (n < 2) { + quad[2] = '='; + } + for (i = 0; i < 4; i++) { + ret += quad[i]; + } + } + return ret; + } //base64_encode + + /// Used to base64 decode data. Input is the encoded data as std::string, output is the plaintext data as std::string. + /// \param encoded_string Base64 encoded data to decode. + /// \returns Plaintext decoded data. + std::string Base64::decode(std::string const & encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + while (in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++ ] = encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) { + char_array_4[i] = chars.find(char_array_4[i]); + } + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + for (i = 0; (i < 3); i++) { + ret += char_array_3[i]; + } + i = 0; + } + } + if (i) { + for (j = i; j < 4; j++) { + char_array_4[j] = 0; + } + for (j = 0; j < 4; j++) { + char_array_4[j] = chars.find(char_array_4[j]); + } + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + for (j = 0; (j < i - 1); j++) + ret += char_array_3[j]; + } + return ret; + } + + + /// Encodes a single character as two hex digits in string form. + std::string Hex::chr(char dec){ + char dig1 = (dec & 0xF0) >> 4; + char dig2 = (dec & 0x0F); + if (dig1 <= 9) dig1 += 48; + if (10 <= dig1 && dig1 <= 15) dig1 += 97 - 10; + if (dig2 <= 9) dig2 += 48; + if (10 <= dig2 && dig2 <= 15) dig2 += 97 - 10; + std::string r; + r.append(&dig1, 1); + r.append(&dig2, 1); + return r; + } + + /// urlencodes std::string data, leaving only the characters A-Za-z0-9~!&()' alone. + std::string URL::encode(const std::string & c){ + std::string escaped = ""; + int max = c.length(); + for (int i = 0; i < max; i++) { + if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') || ('A' <= c[i] && c[i] <= 'Z') + || (c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'')) { + escaped.append(&c[i], 1); + } else { + escaped.append("%"); + escaped.append(Hex::chr(c[i])); + } + } + return escaped; + } + + /// urldecodes std::string data, parsing out both %-encoded characters and +-encoded spaces. + std::string URL::decode(const std::string & in){ + std::string out; + for (unsigned int i = 0; i < in.length(); ++i) { + if (in[i] == '%') { + char tmp = 0; + ++i; + if (i < in.length()) { + tmp = Hex::ord(in[i]) << 4; + } + ++i; + if (i < in.length()) { + tmp += Hex::ord(in[i]); + } + out += tmp; + } else { + if (in[i] == '+') { + out += ' '; + } else { + out += in[i]; + } + } + } + return out; + } + +}//Encodings namespace + diff --git a/lib/encode.h b/lib/encode.h new file mode 100644 index 00000000..c7fb2eac --- /dev/null +++ b/lib/encode.h @@ -0,0 +1,39 @@ +#pragma once +#include + +/// Namespace for character encoding functions and classes +namespace Encodings { + + /// Holds base64 decoding and encoding functions. + class Base64 { + private: + static const std::string chars; + static inline bool is_base64(unsigned char c); + public: + static std::string encode(std::string const input); + static std::string decode(std::string const & encoded_string); + }; + + /// urlencoding and urldecoding functions + class URL { + public: + /// urldecodes std::string data, parsing out both %-encoded characters and +-encoded spaces. + static std::string decode(const std::string & in); + /// urlencodes std::string data, leaving only the characters A-Za-z0-9~!&()' alone. + static std::string encode(const std::string & c); + + }; + + /// Hexadecimal-related functions + class Hex { + public: + /// Decodes a single hexadecimal character to integer, case-insensitive. + static inline int ord(char c){ + return ((c&15) + (((c&64)>>6) | ((c&64)>>3))); + } + /// Encodes a single character as two hex digits in string form. + static std::string chr(char dec); + }; + +} + diff --git a/lib/http_parser.cpp b/lib/http_parser.cpp index d9742f7e..33b9cb53 100644 --- a/lib/http_parser.cpp +++ b/lib/http_parser.cpp @@ -2,6 +2,7 @@ /// Holds all code for the HTTP namespace. #include "http_parser.h" +#include "encode.h" #include "timing.h" /// This constructor creates an empty HTTP::Parser, ready for use for either reading or writing. @@ -232,7 +233,7 @@ void HTTP::Parser::Proxy(Socket::Connection & from, Socket::Connection & to) { unsigned int chunkLen = 0; if (!tmpA.empty()) { for (unsigned int i = 0; i < tmpA.size(); ++i) { - chunkLen = (chunkLen << 4) | unhex(tmpA[i]); + chunkLen = (chunkLen << 4) | Encodings::Hex::ord(tmpA[i]); } if (chunkLen == 0) { getChunks = false; @@ -417,7 +418,7 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer) { parseVars(url.substr(url.find('?') + 1)); //parse GET variables url.erase(url.find('?')); } - url = urlunescape(url); + url = Encodings::URL::decode(url); } else { seenReq = false; } @@ -433,7 +434,7 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer) { parseVars(url.substr(url.find('?') + 1)); //parse GET variables url.erase(url.find('?')); } - url = urlunescape(url); + url = Encodings::URL::decode(url); } else { seenReq = false; } @@ -503,7 +504,7 @@ bool HTTP::Parser::parse(std::string & HTTPbuffer) { unsigned int chunkLen = 0; if (!tmpA.empty()) { for (unsigned int i = 0; i < tmpA.size(); ++i) { - chunkLen = (chunkLen << 4) | unhex(tmpA[i]); + chunkLen = (chunkLen << 4) | Encodings::Hex::ord(tmpA[i]); } if (chunkLen == 0) { getChunks = false; @@ -549,7 +550,7 @@ void HTTP::Parser::parseVars(std::string data) { varname = data.substr(pos, nextpos - pos); varval.clear(); } - SetVar(urlunescape(varname), urlunescape(varval)); + SetVar(Encodings::URL::decode(varname), Encodings::URL::decode(varval)); if (nextpos == std::string::npos) { // in case the string is gigantic break; @@ -610,65 +611,3 @@ void HTTP::Parser::Chunkify(const char * data, unsigned int size, Socket::Connec } } -/// Unescapes URLencoded std::string data. -std::string HTTP::Parser::urlunescape(const std::string & in) { - std::string out; - for (unsigned int i = 0; i < in.length(); ++i) { - if (in[i] == '%') { - char tmp = 0; - ++i; - if (i < in.length()) { - tmp = unhex(in[i]) << 4; - } - ++i; - if (i < in.length()) { - tmp += unhex(in[i]); - } - out += tmp; - } else { - if (in[i] == '+') { - out += ' '; - } else { - out += in[i]; - } - } - } - return out; -} - -/// Helper function for urlunescape. -/// Takes a single char input and outputs its integer hex value. -int HTTP::Parser::unhex(char c) { - return (c >= '0' && c <= '9' ? c - '0' : c >= 'A' && c <= 'F' ? c - 'A' + 10 : c - 'a' + 10); -} - -/// URLencodes std::string data. -std::string HTTP::Parser::urlencode(const std::string & c) { - std::string escaped = ""; - int max = c.length(); - for (int i = 0; i < max; i++) { - if (('0' <= c[i] && c[i] <= '9') || ('a' <= c[i] && c[i] <= 'z') || ('A' <= c[i] && c[i] <= 'Z') - || (c[i] == '~' || c[i] == '!' || c[i] == '*' || c[i] == '(' || c[i] == ')' || c[i] == '\'')) { - escaped.append(&c[i], 1); - } else { - escaped.append("%"); - escaped.append(hex(c[i])); - } - } - return escaped; -} - -/// Helper function for urlescape. -/// Encodes a character as two hex digits. -std::string HTTP::Parser::hex(char dec) { - char dig1 = (dec & 0xF0) >> 4; - char dig2 = (dec & 0x0F); - if (dig1 <= 9) dig1 += 48; - if (10 <= dig1 && dig1 <= 15) dig1 += 97 - 10; - if (dig2 <= 9) dig2 += 48; - if (10 <= dig2 && dig2 <= 15) dig2 += 97 - 10; - std::string r; - r.append(&dig1, 1); - r.append(&dig2, 1); - return r; -} diff --git a/lib/http_parser.h b/lib/http_parser.h index 8f51dd92..c728565c 100644 --- a/lib/http_parser.h +++ b/lib/http_parser.h @@ -37,8 +37,6 @@ namespace HTTP { void Proxy(Socket::Connection & from, Socket::Connection & to); void Clean(); void CleanPreserveHeaders(); - static std::string urlunescape(const std::string & in); - static std::string urlencode(const std::string & in); std::string body; std::string method; std::string url; @@ -59,8 +57,6 @@ namespace HTTP { std::map headers; std::map vars; void Trim(std::string & s); - static int unhex(char c); - static std::string hex(char dec); }; //HTTP::Parser class diff --git a/src/output/output_hss.cpp b/src/output/output_hss.cpp index de66efa2..4e715956 100644 --- a/src/output/output_hss.cpp +++ b/src/output/output_hss.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include #include diff --git a/src/output/output_rtmp.cpp b/src/output/output_rtmp.cpp index 9fa33d9e..11025dfc 100644 --- a/src/output/output_rtmp.cpp +++ b/src/output/output_rtmp.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -57,7 +58,6 @@ namespace Mist { varname = data.substr(pos, nextpos - pos); varval.clear(); } - //SetVar(urlunescape(varname), urlunescape(varval)); if (varname == "track"){ long long int selTrack = JSON::Value(varval).asInt(); @@ -549,7 +549,7 @@ namespace Mist { int playTransaction = amfData.getContentP(1)->NumValue(); int playMessageType = messageType; int playStreamId = streamId; - streamName = amfData.getContentP(3)->StrValue(); + streamName = Encodings::URL::decode(amfData.getContentP(3)->StrValue()); //handle variables if (streamName.find('?') != std::string::npos){