[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/hposton/libhttpserver/master/src/http_request.cpp [Back]  [Original]

/*
     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_view digested_user = get_digested_user();

    int val = MHD_digest_auth_check(underlying_connection, realm.c_str(), digested_user.data(), 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;
}

std::string_view http_request::get_connection_value(std::string_view key, enum MHD_ValueKind kind) const {
    const char* header_c = MHD_lookup_connection_value(underlying_connection, kind, key.data());

    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;

    http::header_view_map* dhr = static_cast(cls);
    (*dhr)[key] = value;
    return MHD_YES;
}

const http::header_view_map http_request::get_headerlike_values(enum MHD_ValueKind kind) const {
    http::header_view_map headers;

    MHD_get_connection_values(underlying_connection, kind, &build_request_header, reinterpret_cast(&headers));

    return headers;
}

std::string_view http_request::get_header(std::string_view key) const {
    return get_connection_value(key, MHD_HEADER_KIND);
}

const http::header_view_map http_request::get_headers() const {
    return get_headerlike_values(MHD_HEADER_KIND);
}

std::string_view http_request::get_footer(std::string_view key) const {
    return get_connection_value(key, MHD_FOOTER_KIND);
}

const http::header_view_map http_request::get_footers() const {
    return get_headerlike_values(MHD_FOOTER_KIND);
}

std::string_view http_request::get_cookie(std::string_view key) const {
    return get_connection_value(key, MHD_COOKIE_KIND);
}

const http::header_view_map http_request::get_cookies() const {
    return get_headerlike_values(MHD_COOKIE_KIND);
}

void http_request::populate_args() const {
    if (!cache->unescaped_args.empty()) {
        return;
    }
    arguments_accumulator aa;
    aa.unescaper = unescaper;
    aa.arguments = &cache->unescaped_args;
    MHD_get_connection_values(underlying_connection, MHD_GET_ARGUMENT_KIND, &build_request_args, reinterpret_cast(&aa));
}

http_arg_value http_request::get_arg(std::string_view key) const {
    populate_args();

    auto it = cache->unescaped_args.find(key);
    if (it != cache->unescaped_args.end()) {
        http_arg_value arg;
        arg.values.reserve(it->second.size());
        for (const auto& value : it->second) {
            arg.values.push_back(value);
        }
        return arg;
    }
    return http_arg_value();
}

std::string_view http_request::get_arg_flat(std::string_view key) const {
    auto const it = cache->unescaped_args.find(key);

    if (it != cache->unescaped_args.end()) {
        return it->second[0];
    }

    return get_connection_value(key, MHD_GET_ARGUMENT_KIND);
}

const http::arg_view_map http_request::get_args() const {
    populate_args();

    http::arg_view_map arguments;
    for (const auto& [key, value] : cache->unescaped_args) {
        auto& arg_values = arguments[key];
        for (const auto& v : value) {
            arg_values.values.push_back(v);
        }
    }
    return arguments;
}

const std::map http_request::get_args_flat() const {
    populate_args();
    std::map ret;
    for (const auto&[key, val] : cache->unescaped_args) {
        ret[key] = val[0];
    }
    return ret;
}

http::file_info& http_request::get_or_create_file_info(const std::string& key, const std::string& upload_file_name) {
    return files[key][upload_file_name];
}

std::string_view http_request::get_querystring() const {
    if (!cache->querystring.empty()) {
        return cache->querystring;
    }

    MHD_get_connection_values(underlying_connection, MHD_GET_ARGUMENT_KIND, &build_request_querystring, reinterpret_cast(&cache->querystring));

    return cache->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].push_back(value);
    return MHD_YES;
}

MHD_Result http_request::build_request_querystring(void *cls, enum MHD_ValueKind kind, const char *key_value, 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_view key = key_value;
    std::string_view value = ((arg_value == nullptr) ? "" : arg_value);

    // Limit to a single allocation.
    querystring->reserve(querystring->size() + key.size() + value.size() + 3);

    *querystring += ((*querystring == "") ? "?" : "&");
    *querystring += key;
    *querystring += "=";
    *querystring += value;

    return MHD_YES;
}

void http_request::fetch_user_pass() const {
    char* password = nullptr;
    auto* username = MHD_basic_auth_get_username_password(underlying_connection, &password);

    if (username != nullptr) {
        cache->username = username;
        MHD_free(username);
    }
    if (password != nullptr) {
        cache->password = password;
        MHD_free(password);
    }
}

std::string_view http_request::get_user() const {
    if (!cache->username.empty()) {
        return cache->username;
    }
    fetch_user_pass();
    return cache->username;
}

std::string_view http_request::get_pass() const {
    if (!cache->password.empty()) {
        return cache->password;
    }
    fetch_user_pass();
    return cache->password;
}

std::string_view http_request::get_digested_user() const {
    if (!cache->digested_user.empty()) {
        return cache->digested_user;
    }

    char* digested_user_c = MHD_digest_auth_get_username(underlying_connection);

    cache->digested_user = EMPTY;
    if (digested_user_c != nullptr) {
        cache->digested_user = digested_user_c;
        free(digested_user_c);
    }

    return cache->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

std::string_view http_request::get_requestor() const {
    if (!cache->requestor_ip.empty()) {
        return cache->requestor_ip;
    }

    const MHD_ConnectionInfo * conninfo = MHD_get_connection_info(underlying_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS);

    cache->requestor_ip = http::get_ip_str(conninfo->client_addr);
    return cache->requestor_ip;
}

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

Web Proxy Viewer  |  New URL  |  Original Page