/*
This file is part of libhttpserver
Copyright (C) 2011-2019 Sebastiano Merlino
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
USA
*/
#include "httpserver/http_request.hpp"
#include
#include
#include
#include "httpserver/http_utils.hpp"
#include "httpserver/string_utilities.hpp"
namespace httpserver {
const char http_request::EMPTY[] = "";
struct arguments_accumulator {
unescaper_ptr unescaper;
std::map* arguments;
};
void http_request::set_method(const std::string& method) {
this->method = string_utilities::to_upper_copy(method);
}
bool http_request::check_digest_auth(const std::string& realm, const std::string& password, int nonce_timeout, bool* reload_nonce) const {
std::string digested_user = get_digested_user();
int val = MHD_digest_auth_check(underlying_connection, realm.c_str(), digested_user.c_str(), password.c_str(), nonce_timeout);
if (val == MHD_INVALID_NONCE) {
*reload_nonce = true;
return false;
} else if (val == MHD_NO) {
*reload_nonce = false;
return false;
}
*reload_nonce = false;
return true;
}
const std::string http_request::get_connection_value(const std::string& key, enum MHD_ValueKind kind) const {
const char* header_c = MHD_lookup_connection_value(underlying_connection, kind, key.c_str());
if (header_c == nullptr) return EMPTY;
return header_c;
}
MHD_Result http_request::build_request_header(void *cls, enum MHD_ValueKind kind, const char *key, const char *value) {
// Parameters needed to respect MHD interface, but not used in the implementation.
std::ignore = kind;
std::map* dhr = static_cast*>(cls);
(*dhr)[key] = value;
return MHD_YES;
}
const std::map http_request::get_headerlike_values(enum MHD_ValueKind kind) const {
std::map headers;
MHD_get_connection_values(underlying_connection, kind, &build_request_header, reinterpret_cast(&headers));
return headers;
}
const std::string http_request::get_header(const std::string& key) const {
return get_connection_value(key, MHD_HEADER_KIND);
}
const std::map http_request::get_headers() const {
return get_headerlike_values(MHD_HEADER_KIND);
}
const std::string http_request::get_footer(const std::string& key) const {
return get_connection_value(key, MHD_FOOTER_KIND);
}
const std::map http_request::get_footers() const {
return get_headerlike_values(MHD_FOOTER_KIND);
}
const std::string http_request::get_cookie(const std::string& key) const {
return get_connection_value(key, MHD_COOKIE_KIND);
}
const std::map http_request::get_cookies() const {
return get_headerlike_values(MHD_COOKIE_KIND);
}
const std::string http_request::get_arg(const std::string& key) const {
std::map::const_iterator it = args.find(key);
if (it != args.end()) {
return it->second;
}
return get_connection_value(key, MHD_GET_ARGUMENT_KIND);
}
const std::map http_request::get_args() const {
std::map arguments;
arguments.insert(args.begin(), args.end());
arguments_accumulator aa;
aa.unescaper = unescaper;
aa.arguments = &arguments;
MHD_get_connection_values(underlying_connection, MHD_GET_ARGUMENT_KIND, &build_request_args, reinterpret_cast(&aa));
return arguments;
}
const std::string http_request::get_querystring() const {
std::string querystring = "";
MHD_get_connection_values(underlying_connection, MHD_GET_ARGUMENT_KIND, &build_request_querystring, reinterpret_cast(&querystring));
return querystring;
}
MHD_Result http_request::build_request_args(void *cls, enum MHD_ValueKind kind, const char *key, const char *arg_value) {
// Parameters needed to respect MHD interface, but not used in the implementation.
std::ignore = kind;
arguments_accumulator* aa = static_cast(cls);
std::string value = ((arg_value == nullptr) ? "" : arg_value);
http::base_unescaper(&value, aa->unescaper);
(*aa->arguments)[key] = value;
return MHD_YES;
}
MHD_Result http_request::build_request_querystring(void *cls, enum MHD_ValueKind kind, const char *key, const char *arg_value) {
// Parameters needed to respect MHD interface, but not used in the implementation.
std::ignore = kind;
std::string* querystring = static_cast(cls);
std::string value = ((arg_value == nullptr) ? "" : arg_value);
int buffer_size = std::string(key).size() + value.size() + 3;
char* buf = new char[buffer_size];
if (*querystring == "") {
snprintf(buf, buffer_size, "?%s=%s", key, value.c_str());
*querystring = std::string(buf);
} else {
snprintf(buf, buffer_size, "&%s=%s", key, value.c_str());
*querystring += std::string(buf);
}
delete[] buf;
return MHD_YES;
}
const std::string http_request::get_user() const {
char* username = nullptr;
char* password = nullptr;
username = MHD_basic_auth_get_username_password(underlying_connection, &password);
if (password != nullptr) free(password);
std::string user;
if (username != nullptr) user = username;
free(username);
return user;
}
const std::string http_request::get_pass() const {
char* username = nullptr;
char* password = nullptr;
username = MHD_basic_auth_get_username_password(underlying_connection, &password);
if (username != nullptr) free(username);
std::string pass;
if (password != nullptr) pass = password;
free(password);
return pass;
}
const std::string http_request::get_digested_user() const {
char* digested_user_c = nullptr;
digested_user_c = MHD_digest_auth_get_username(underlying_connection);
std::string digested_user = EMPTY;
if (digested_user_c != nullptr) {
digested_user = digested_user_c;
free(digested_user_c);
}
return digested_user;
}
#ifdef HAVE_GNUTLS
bool http_request::has_tls_session() const {
const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(underlying_connection, MHD_CONNECTION_INFO_GNUTLS_SESSION);
return (conninfo != nullptr);
}
gnutls_session_t http_request::get_tls_session() const {
const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(underlying_connection, MHD_CONNECTION_INFO_GNUTLS_SESSION);
return static_cast(conninfo->tls_session);
}
#endif // HAVE_GNUTLS
const std::string http_request::get_requestor() const {
const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(underlying_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
return http::get_ip_str(conninfo->client_addr);
}
uint16_t http_request::get_requestor_port() const {
const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(underlying_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);
return http::get_port(conninfo->client_addr);
}
std::ostream &operator<< (std::ostream &os, const http_request &r) {
os << r.get_method() << " Request [user:\"" << r.get_user() << "\" pass:\"" << r.get_pass() << "\"] path:\""
<< r.get_path() << "\"" << std::endl;
http::dump_header_map(os, "Headers", r.get_headers());
http::dump_header_map(os, "Footers", r.get_footers());
http::dump_header_map(os, "Cookies", r.get_cookies());
http::dump_arg_map(os, "Query Args", r.get_args());
os << " Version [ " << r.get_version() << " ] Requestor [ " << r.get_requestor()
<< " ] Port [ " << r.get_requestor_port() << " ]" << std::endl;
return os;
}
} // namespace httpserver