#include #include #include //#include #include "HttpCodec.hh" #include "loggers.hh" #include "LibItsHttp_TypesAndValues.hh" int HttpCodec::encode (const LibItsHttp__TypesAndValues::HttpMessage& msg, OCTETSTRING& data) { loggers::get_instance().log_msg(">>> HttpCodec::encode: ", (const Base_Type&)msg); TTCN_EncDec::clear_error(); TTCN_Buffer encoding_buffer; int result; if (msg.ischosen(LibItsHttp__TypesAndValues::HttpMessage::ALT_request)) { result = encode_request(msg.request(), encoding_buffer); } else if (msg.ischosen(LibItsHttp__TypesAndValues::HttpMessage::ALT_response)) { //result = encode_response(msg.response(), encoding_buffer); } else { loggers::get_instance().warning("HttpCodec::encode: Unbound HttpMessage"); return -1; } data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data()); loggers::get_instance().log_msg("<<< HttpCodec::encode: data=", data); return result; } int HttpCodec::decode (const OCTETSTRING& data, LibItsHttp__TypesAndValues::HttpMessage& msg, Params* params) { loggers::get_instance().log_msg(">>> HttpCodec::decode: data=", data); TTCN_EncDec::clear_error(); TTCN_Buffer decoding_buffer(data); loggers::get_instance().log_to_hexa("HttpCodec::decode: decoding_buffer=", decoding_buffer); _params = params; // Get the first line (e.g. HTTP/1.1 302 Found or POST / HTTP/1.1) CHARSTRING message_id; if (get_line(decoding_buffer, message_id) == -1) { return -1; } loggers::get_instance().log_msg("HttpCodec::decode: message_id: ", message_id); // Extract parameters try { std::string str(static_cast(message_id)); std::regex rgx ("\\s*(\\w+)/"); std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); std::smatch m = *begin; loggers::get_instance().log("HttpCodec::decode: %d - %s", m.size(), m[0].str().c_str()); if (m[0].str().compare("HTTP/") == 0) { // HTTP response LibItsHttp__TypesAndValues::Response response; std::regex rgx ("\\s*HTTP/(\\d)\\.(\\d)\\s+(\\d+)\\s+(\\w+)"); std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); std::smatch m = *begin; if (m.size() != 5) { loggers::get_instance().error("HttpCodec::decode: Unsupported tag"); return -1; } response.version__major() = std::stoi(m[1].str().c_str()); response.version__minor() = std::stoi(m[2].str().c_str()); response.statuscode() = std::stoi(m[3].str().c_str()); response.statustext() = CHARSTRING(m[4].str().c_str()); LibItsHttp__TypesAndValues::HeaderLines headers; decode_headers(decoding_buffer, headers); response.header() = headers; loggers::get_instance().log_to_hexa("Before decoding Body: ", decoding_buffer); CHARSTRING body(""); if (decode_body(decoding_buffer, body) == -1) { response.body().set_to_omit(); } else if (body.lengthof() == 0) { response.body().set_to_omit(); } else { // TODO } msg.response() = response; } else { // HTTP request LibItsHttp__TypesAndValues::Request request; std::regex rgx ("\\s*(\\w+)\\s+(.+)\\s+HTTP/(\\d)\\.(\\d)"); std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); std::smatch m = *begin; if (m.size() != 5) { loggers::get_instance().error("HttpCodec::decode: Unsupported tag"); return -1; } request.method() = CHARSTRING(m[1].str().c_str()); request.uri() = CHARSTRING(m[2].str().c_str()); request.version__major() = std::stoi(m[3].str().c_str()); request.version__minor() = std::stoi(m[4].str().c_str()); LibItsHttp__TypesAndValues::HeaderLines headers; decode_headers(decoding_buffer, headers); request.header() = headers; loggers::get_instance().log_to_hexa("Before decoding Body: ", decoding_buffer); CHARSTRING body(""); if (decode_body(decoding_buffer, body) == -1) { request.body().set_to_omit(); } else if (body.lengthof() == 0) { request.body().set_to_omit(); } else { // TODO } msg.request() = request; } loggers::get_instance().log_msg("<<< HttpCodec::decode: ", (const Base_Type&)msg); return 0; } catch(const std::logic_error& e) { return -1; } } int HttpCodec::encode_request(const LibItsHttp__TypesAndValues::Request& p_request, TTCN_Buffer& p_encoding_buffer) { loggers::get_instance().log_msg(">>> HttpCodec::encode_request: ", (const Base_Type&)p_request); const OPTIONAL& v = p_request.body(); CHARSTRING body(""); if (v.ispresent()) { body = static_cast(*v.get_opt_value()); loggers::get_instance().log_msg("HttpCodec::encode_request: body: ", body); } // Encode generic part p_encoding_buffer.put_cs(p_request.method()); p_encoding_buffer.put_c(' '); p_encoding_buffer.put_cs(p_request.uri()); p_encoding_buffer.put_cs(" HTTP/"); p_encoding_buffer.put_cs(int2str(p_request.version__major())); p_encoding_buffer.put_c('.'); p_encoding_buffer.put_cs(int2str(p_request.version__minor())); p_encoding_buffer.put_cs("\r\n"); // Encode headers const LibItsHttp__TypesAndValues::HeaderLines& headers = p_request.header(); for (int i = 0; i < headers.size_of(); i++) { const LibItsHttp__TypesAndValues::HeaderLine& header = headers[i]; loggers::get_instance().log_msg("HttpCodec::encode_request: Processing header ", header.header__name()); p_encoding_buffer.put_cs(header.header__name()); p_encoding_buffer.put_cs(": "); if (std::string(static_cast(header.header__name())).compare("Content-Length") == 0) { loggers::get_instance().log("HttpCodec::encode_request: body length: %d", body.lengthof()); p_encoding_buffer.put_cs(int2str(body.lengthof())); } else { if (header.header__value().size_of() > 0) { loggers::get_instance().log_msg("HttpCodec::encode_request: Processing value ", header.header__value()[0]); p_encoding_buffer.put_cs(header.header__value()[0]); int j = 1; while (j < header.header__value().size_of()) { p_encoding_buffer.put_cs("; "); loggers::get_instance().log_msg("HttpCodec::encode_request: Processing value ", header.header__value()[j]); p_encoding_buffer.put_cs(header.header__value()[j]); j += 1; } // End of 'while' statement } } p_encoding_buffer.put_cs("\r\n"); } // End of 'for' statement if (body.lengthof() != 0) { p_encoding_buffer.put_cs(body); } p_encoding_buffer.put_cs("\r\n"); return 0; } int HttpCodec::decode_headers(TTCN_Buffer& decoding_buffer, LibItsHttp__TypesAndValues::HeaderLines& headers) { loggers::get_instance().log(">>> HttpCodec::decode_headers"); loggers::get_instance().log_to_hexa("HttpCodec::decode_headers", decoding_buffer); CHARSTRING cstr; int i = 0; while (true) { switch(get_line(decoding_buffer, cstr, true)) { case 0: { loggers::get_instance().log_msg("HttpCodec::decode_headers: ", cstr); LibItsHttp__TypesAndValues::HeaderLine header; if (decode_header(cstr, header) == -1) { loggers::get_instance().warning("HttpCodec::decode_headers: Failed to decode header %s", static_cast(cstr)); return -1; } headers[i++] = header; } break; case 1: loggers::get_instance().log_msg("<<< HttpCodec::decode_headers: ", headers); return 0; case -1: loggers::get_instance().warning("HttpCodec::decode_headers: Failed to decode headers"); return -1; } // End of 'switch' statement } // End of 'while' statement } int HttpCodec::decode_header(CHARSTRING& header_line, LibItsHttp__TypesAndValues::HeaderLine& header) { loggers::get_instance().log_msg(">>> HttpCodec::decode_header", header_line); try { std::string str(static_cast(header_line)); std::regex rgx ("([0-9a-zA-Z-]+)\\:\\s+(.+)(;(.+))*"); std::sregex_iterator begin(str.cbegin(), str.cend(), rgx); std::smatch m = *begin; if (m.size() < 5) { return -1; } header.header__name() = CHARSTRING(m[1].str().c_str()); for (unsigned int j = 0; j < m.size(); j++) { if (m[j + 2].str().length() == 0) { break; } header.header__value()[j] = CHARSTRING(m[j + 2].str().c_str()); } return 0; } catch(const std::logic_error& e) { return -1; } } int HttpCodec::decode_body(TTCN_Buffer& decoding_buffer, CHARSTRING& body) { loggers::get_instance().log(">>> HttpCodec::decode_body"); loggers::get_instance().log_to_hexa("HttpCodec::decode_body", decoding_buffer); loggers::get_instance().log_msg("<<< HttpCodec::decode_body: ", body); return -1; } int HttpCodec::get_line(TTCN_Buffer& buffer, CHARSTRING& to, const bool concatenate_header_lines) { unsigned int i = 0; const unsigned char *cc_to = buffer.get_read_data(); // Sanity checks if(buffer.get_read_len() == 0) { return -1; } while (true) { // Skip spaces, and emplty lines for( ; i < buffer.get_read_len() && cc_to[i] != '\0' && cc_to[i] != '\r' && cc_to[i] != '\n'; i++); if(i >= buffer.get_read_len()) { // No more characters to process to = CHARSTRING(""); return -1; } else if(cc_to[i] == '\n') { // New line found, we don't care is '\r' is missing if ((i > 0) && ((i + 1) < buffer.get_read_len()) && concatenate_header_lines && ((cc_to[i + 1] == ' ') || (cc_to[i + 1] == '\t'))) { i += 1; // Skip it } else { to = CHARSTRING(i, (const char*)cc_to); buffer.set_pos(buffer.get_pos() + i + 1); return i == 0 ? 1 : 0; } } else { if ((i + 1) < buffer.get_read_len() && cc_to[i + 1] != '\n') { return -1; } else if(i > 0 && (i + 2) < buffer.get_read_len() && concatenate_header_lines && (cc_to[i+2] == ' ' || cc_to[i+2] == '\t')) { i += 2; } else { to = CHARSTRING(i, (const char*)cc_to); buffer.set_pos(buffer.get_pos() + i + 2); return i == 0 ? 1 : 0; } } } // End of 'while' statement }