Newer
Older
#include <stdexcept>
#include <regex>
#include <string>
//#include <typeinfo>
#include "loggers.hh"
#include "LibItsHttp_TypesAndValues.hh"
int http_codec::encode (const LibItsHttp__TypesAndValues::HttpMessage& msg, OCTETSTRING& data)
loggers::get_instance().log_msg(">>> http_codec::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("http_codec::encode: Unbound HttpMessage");
return -1;
}
data = OCTETSTRING(encoding_buffer.get_len(), encoding_buffer.get_data());
loggers::get_instance().log_msg("<<< http_codec::encode: data=", data);
int http_codec::decode (const OCTETSTRING& data, LibItsHttp__TypesAndValues::HttpMessage& msg, params* params)
loggers::get_instance().log_msg(">>> http_codec::decode: data=", data);
TTCN_EncDec::clear_error();
TTCN_Buffer decoding_buffer(data);
loggers::get_instance().log_to_hexa("http_codec::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("http_codec::decode: message_id: ", message_id);
// Extract parameters
try {
std::string str(static_cast<const char*>(message_id));
std::regex rgx ("\\s*(\\w+)/");
std::sregex_iterator begin(str.cbegin(), str.cend(), rgx);
std::smatch m = *begin;
loggers::get_instance().log("http_codec::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("http_codec::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("http_codec::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("<<< http_codec::decode: ", (const Base_Type&)msg);
return 0;
}
catch(const std::logic_error& e) {
return -1;
}
}
int http_codec::encode_request(const LibItsHttp__TypesAndValues::Request& p_request, TTCN_Buffer& p_encoding_buffer)
loggers::get_instance().log_msg(">>> http_codec::encode_request: ", (const Base_Type&)p_request);
const OPTIONAL<CHARSTRING>& v = p_request.body();
CHARSTRING body("");
if (v.ispresent()) {
body = static_cast<const CHARSTRING&>(*v.get_opt_value());
loggers::get_instance().log_msg("http_codec::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("http_codec::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<const char*>(header.header__name())).compare("Content-Length") == 0) {
loggers::get_instance().log("http_codec::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("http_codec::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("http_codec::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 http_codec::decode_headers(TTCN_Buffer& decoding_buffer, LibItsHttp__TypesAndValues::HeaderLines& headers) {
loggers::get_instance().log(">>> http_codec::decode_headers");
loggers::get_instance().log_to_hexa("http_codec::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("http_codec::decode_headers: ", cstr);
LibItsHttp__TypesAndValues::HeaderLine header;
if (decode_header(cstr, header) == -1) {
loggers::get_instance().warning("http_codec::decode_headers: Failed to decode header %s", static_cast<const char*>(cstr));
return -1;
}
headers[i++] = header;
}
break;
case 1:
loggers::get_instance().log_msg("<<< http_codec::decode_headers: ", headers);
loggers::get_instance().warning("http_codec::decode_headers: Failed to decode headers");
return -1;
} // End of 'switch' statement
} // End of 'while' statement
}
int http_codec::decode_header(CHARSTRING& header_line, LibItsHttp__TypesAndValues::HeaderLine& header) {
loggers::get_instance().log_msg(">>> http_codec::decode_header", header_line);
try {
std::string str(static_cast<const char*>(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 http_codec::decode_body(TTCN_Buffer& decoding_buffer, CHARSTRING& body) {
loggers::get_instance().log(">>> http_codec::decode_body");
loggers::get_instance().log_to_hexa("http_codec::decode_body", decoding_buffer);
loggers::get_instance().log_msg("<<< http_codec::decode_body: ", body);
int http_codec::get_line(TTCN_Buffer& buffer, CHARSTRING& to, const bool concatenate_header_lines) {
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
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
}