X Tutup
#include "Init.h" #include "socket/AdapterDefault.h" #include "transfer/FileIncoming.h" #include "transfer/http2/Http2.h" #include "utils/Utils.h" #include "server/protocol/ServerHttp1.h" #include "server/protocol/ServerHttp2.h" #include #include Socket::Adapter *createSocketAdapter( Transfer::app_request *request, void *addr ) { if (request->tls_session) { return new (addr) Socket::AdapterTls(request->tls_session); } return new (addr) Socket::AdapterDefault(request->socket); } void destroySocketAdapter(Socket::Adapter *adapter) { if (adapter) { adapter->~Adapter(); } } std::string utf8ToLocal(const std::string &u8str) { std::locale loc(""); std::wstring_convert > conv; std::wstring wstr = conv.from_bytes(u8str); std::string str(wstr.size(), 0); std::use_facet >(loc).narrow( wstr.data(), wstr.data() + wstr.size(), '?', &str.front() ); return str; } std::string getClearPath(const std::string &path) { const size_t pos = path.find_first_of("?#"); const std::string clean = Utils::urlDecode( std::string::npos == pos ? path : path.substr(0, pos) ); #ifdef WIN32 return utf8ToLocal(clean); #else return clean; #endif } static void getIncomingVars( std::unordered_multimap ¶ms, const std::string &uri ) { const size_t start = uri.find('?'); if (std::string::npos == start) { return; } const size_t finish = uri.find('#'); if (finish < start) { return; } for ( size_t var_pos = start + 1, var_end = 0; std::string::npos != var_end; var_pos = var_end + 1 ) { var_end = uri.find('&', var_pos); if (var_end > finish) { var_end = std::string::npos; } size_t delimiter = uri.find('=', var_pos); if (delimiter >= var_end) { std::string var_name = Utils::urlDecode( uri.substr( var_pos, std::string::npos != var_end ? var_end - var_pos : std::string::npos ) ); params.emplace( std::move(var_name), std::string() ); } else { std::string var_name = Utils::urlDecode( uri.substr( var_pos, delimiter - var_pos ) ); ++delimiter; std::string var_value = Utils::urlDecode( uri.substr( delimiter, std::string::npos != var_end ? var_end - delimiter : std::string::npos ) ); params.emplace( std::move(var_name), std::move(var_value) ); } } } bool initServerObjects( HttpServer::Request *procRequest, HttpServer::Response *procResponse, const Transfer::app_request *request, Socket::Adapter *socket_adapter ) { const uint8_t *src = reinterpret_cast(request->request_data); size_t protocol_number; src = Utils::unpackNumber(&protocol_number, src); Transfer::ProtocolVariant protocol_variant = static_cast(protocol_number); HttpServer::ServerProtocol *prot = nullptr; std::string document_root; std::string host; std::string path; std::string method; std::unordered_multimap params; std::unordered_multimap headers; std::unordered_multimap data; std::unordered_multimap files; std::unordered_multimap cookies; bool success = true; switch (protocol_variant) { case Transfer::ProtocolVariant::HTTP_1: { src = Utils::unpackString(document_root, src); src = Utils::unpackString(host, src); src = Utils::unpackString(path, src); src = Utils::unpackString(method, src); src = Utils::unpackContainer(headers, src); src = Utils::unpackContainer(data, src); src = Utils::unpackFilesIncoming(files, src); auto const it_cookie = headers.find("cookie"); if (headers.cend() != it_cookie) { Utils::parseCookies(it_cookie->second, cookies); } getIncomingVars(params, path); prot = new HttpServer::ServerHttp1(socket_adapter); break; } case Transfer::ProtocolVariant::HTTP_2: { src = Utils::unpackString(document_root, src); src = Utils::unpackString(host, src); src = Utils::unpackString(path, src); src = Utils::unpackString(method, src); size_t number; src = Utils::unpackNumber(&number, src); const uint32_t stream_id = static_cast(number); Http2::ConnectionSettings settings; src = Utils::unpackNumber(&number, src); settings.header_table_size = static_cast(number); src = Utils::unpackNumber(&number, src); settings.enable_push = static_cast(number); src = Utils::unpackNumber(&number, src); settings.max_concurrent_streams = static_cast(number); src = Utils::unpackNumber(&number, src); settings.initial_window_size = static_cast(number); src = Utils::unpackNumber(&number, src); settings.max_frame_size = static_cast(number); src = Utils::unpackNumber(&number, src); settings.max_header_list_size = static_cast(number); std::deque > dynamic_table; src = Utils::unpackVector(dynamic_table, src); std::mutex *mtx = nullptr; src = Utils::unpackPointer(reinterpret_cast(&mtx), src); src = Utils::unpackContainer(headers, src); src = Utils::unpackContainer(data, src); src = Utils::unpackFilesIncoming(files, src); auto const it_cookie = headers.find("cookie"); if (headers.cend() != it_cookie) { Utils::parseCookies(it_cookie->second, cookies); } getIncomingVars(params, path); Http2::OutStream *stream = new Http2::OutStream( stream_id, settings, Http2::DynamicTable( settings.header_table_size, settings.max_header_list_size, std::move(dynamic_table) ), mtx ); prot = new HttpServer::ServerHttp2(socket_adapter, stream); break; } default: { success = false; break; } } *procRequest = HttpServer::Request { prot, std::move(document_root), std::move(host), std::move(path), std::move(method), std::move(params), std::move(headers), std::move(data), std::move(files), std::move(cookies), protocol_variant }; *procResponse = HttpServer::Response { prot, protocol_variant, std::unordered_map(), Http::StatusCode::EMPTY }; return success; } void freeProtocolData(HttpServer::Response *response) { if (response) { delete response->prot; } } bool isSwitchingProtocols( const HttpServer::Request &request, HttpServer::Response &response ) { // Check for https is not set if (request.prot->getSocket()->get_tls_session() != nullptr) { return false; } // Check for upgrade to https /*auto const it_upgrade_insecure = request.headers.find("upgrade-insecure-requests"); if (request.headers.cend() != it_upgrade_insecure) { if (it_upgrade_insecure->second == "1") { response.status = Http::StatusCode::MOVED_TEMPORARILY; response.headers["location"] = "https://" + request.host + request.path; response.headers["strict-transport-security"] = "max-age=86400"; const std::string headers = "HTTP/1.1 307 Moved Temporarily\r\nLocation: https://" + request.host + request.path + "\r\nStrict-Transport-Security: max-age=86400\r\n\r\n"; response.prot->getSocket()->nonblock_send(headers, std::chrono::milliseconds(5000) ); return true; } }*/ // Check if switch protocol to h2c auto const it_upgrade = request.headers.find("upgrade"); if (request.headers.cend() == it_upgrade) { return false; } auto const it_connection = request.headers.find("connection"); if (request.headers.cend() == it_connection) { return false; } std::vector list = Utils::explode(it_connection->second, ','); bool is_upgrade = false; for (auto &item : list) { Utils::toLower(item); if ("upgrade" == item) { is_upgrade = true; break; } } if (false == is_upgrade) { return false; } const std::string &upgrade = it_upgrade->second; if ("h2c" != upgrade) { return false; } auto const it_settings = request.headers.find("http2-settings"); if (request.headers.cend() == it_settings) { return false; } response.headers["connection"] = "upgrade"; response.headers["upgrade"] = "h2c"; const std::string headers = "HTTP/1.1 101 Switching Protocols\r\nConnection: Upgrade\r\nUpgrade: h2c\r\n\r\n"; response.prot->getSocket()->nonblock_send( headers, std::chrono::milliseconds(5000) ); return true; }
X Tutup