# HG changeset patch # User František Kučera # Date 1650494634 -7200 # Node ID 315d985f8424f6622d07a96ca5cdd79a30b68379 # Parent b04bde9083d474846be5d28d2ea83e483a89aea8 use common hex function, serve also binary content, not only text diff -r b04bde9083d4 -r 315d985f8424 src/HTTPDHandler.h --- a/src/HTTPDHandler.h Thu Apr 21 00:23:08 2022 +0200 +++ b/src/HTTPDHandler.h Thu Apr 21 00:43:54 2022 +0200 @@ -39,6 +39,7 @@ #include "Configuration.h" #include "HTTPServer.h" +#include "Hex.h" namespace relpipe { namespace tr { @@ -144,11 +145,11 @@ relationalWriter->writeAttribute(exchangeId); relationalWriter->writeAttribute(convertor.from_bytes(request.url)); relationalWriter->writeAttribute(convertor.from_bytes(request.method)); - relationalWriter->writeAttribute(bodyToText(convertor, request.body)); - relationalWriter->writeAttribute(bodyToHex(convertor, request.body)); + relationalWriter->writeAttribute(Hex::toTxt(request.body)); + relationalWriter->writeAttribute(Hex::toHex(request.body)); relationalWriter->writeAttribute(&requestSize, typeid (requestSize)); - relationalWriter->writeAttribute(bodyToText(convertor, response.body)); - relationalWriter->writeAttribute(bodyToHex(convertor, response.body)); + relationalWriter->writeAttribute(Hex::toTxt(response.body)); + relationalWriter->writeAttribute(Hex::toHex(response.body)); relationalWriter->writeAttribute(&responseSize, typeid (responseSize)); relationalWriter->writeAttribute(std::to_wstring(response.code)); @@ -182,26 +183,6 @@ } - relpipe::common::type::StringX bodyToText(std::wstring_convert < codecvt_utf8>&convertor, const std::string& body, bool* validEncoding = nullptr) { - try { - if (validEncoding) *validEncoding = true; - // TODO: use encoding from the HTTP response headers instead of the constant one? - return convertor.from_bytes(body); - } catch (...) { - if (validEncoding) *validEncoding = false; - std::stringstream filtered; - for (char ch : body) filtered << (ch >= ' ' && ch < 127 ? ch : '.'); - return convertor.from_bytes(filtered.str()); - } - } - - relpipe::common::type::StringX bodyToHex(std::wstring_convert < codecvt_utf8>&convertor, const std::string& body) { - std::stringstream hex; - hex << std::hex << std::setfill('0') << std::hex; - for (size_t i = 0, size = body.size(); i < size; i++) hex << std::setw(2) << (0xff & body[i]); - return convertor.from_bytes(hex.str()); - } - std::string generateExchangeId() { char buffer[37]; uuid_t uuid; @@ -284,10 +265,12 @@ if (attributeName == L"url") responseTemplate.url = std::regex(value.size() ? convertor.to_bytes(value) : ".*"); else if (attributeName == L"method") responseTemplate.method = std::regex(value.size() ? convertor.to_bytes(value) : ".*"); else if (attributeName == L"code") responseTemplate.code = std::stoi(value); - else if (attributeName == L"text") responseTemplate.body = convertor.to_bytes(value); - else if (attributeName == L"data") responseTemplate.body = "TODO: read binary data: " + convertor.to_bytes(value); // TODO: read hex/binary request body + else if (attributeName == L"text" && value.size()) responseTemplate.body = convertor.to_bytes(value); + else if (attributeName == L"data" && value.size()) responseTemplate.body = Hex::fromHex(value).str(); + else if (attributeName == L"text"); // keep empty or value from 'data' + else if (attributeName == L"data"); // keep empty or value from 'text' else if (isHeaderAttribute(attributeName)) responseTemplate.headers.push_back(HeaderTemplate(convertor.to_bytes(fetchHeaderName(attributeName)), convertor.to_bytes(value))); // TODO: header encoding? - else throw std::invalid_argument("Unsupported attribute in the request_template relation: " + convertor.to_bytes(attributeName + L" = " + value)); + else throw std::invalid_argument("Unsupported attribute in the response_template relation: " + convertor.to_bytes(attributeName + L" = " + value)); currentAttributeIndex++; diff -r b04bde9083d4 -r 315d985f8424 src/Hex.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Hex.h Thu Apr 21 00:43:54 2022 +0200 @@ -0,0 +1,85 @@ +/** + * Relational pipes + * Copyright © 2022 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include + +namespace relpipe { +namespace tr { +namespace httpd { + +class Hex { +private: + + Hex() { + } + + static char fromHex(wchar_t ch) { + if (L'0' <= ch && ch <= L'9') return ch - L'0'; + else if (L'a' <= ch && ch <= L'f') return ch - L'a' + 10; + else throw std::invalid_argument("Unable to decode hexadeximal string."); + } + +public: + + static std::stringstream fromHex(const std::wstring& hex) { + std::stringstream octets; + + char octet = 0; + + for (size_t i = 0, limit = hex.size(); i < limit; i++) { + if (i % 2 == 0) { + octet = fromHex(hex[i]) << 4; + } else { + octet += fromHex(hex[i]); + octets.put(octet); + } + } + + return octets; + } + + static std::wstring toHex(const std::string& octets) { + std::wstring_convert < codecvt_utf8> convertor; // TODO: do not create converter each time + std::stringstream hex; + hex << std::hex << std::setfill('0') << std::hex; + for (size_t i = 0, size = octets.size(); i < size; i++) hex << std::setw(2) << (0xff & octets[i]); + return convertor.from_bytes(hex.str()); + } + + static std::wstring toTxt(const std::string& octets, bool* validEncoding = nullptr) { + std::wstring_convert < codecvt_utf8> convertor; // TODO: do not create converter each time + try { + if (validEncoding) *validEncoding = true; + // TODO: use encoding from the HTTP response headers instead of the constant one? + return convertor.from_bytes(octets); + } catch (...) { + if (validEncoding) *validEncoding = false; + std::stringstream filtered; + for (char ch : octets) filtered << (ch >= ' ' && ch < 127 ? ch : '.'); + return convertor.from_bytes(filtered.str()); + } + } +}; + +} +} +}