/*
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_utils.hpp"
#if defined(_WIN32) && !defined(__CYGWIN__)
#include
#include
#else // WIN32 check
#include
#include
#include
#include
#include
#endif // WIN32 check
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "httpserver/string_utilities.hpp"
#pragma GCC diagnostic ignored "-Warray-bounds"
#define CHECK_BIT(var, pos) ((var) & (1 sin6_addr), to_ret, INET6_ADDRSTRLEN);
return to_ret;
} else if (AF_INET == sa->sa_family) {
inet_ntop(AF_INET, &((reinterpret_cast(sa))->sin_addr), to_ret, INET_ADDRSTRLEN);
return to_ret;
} else {
throw std::invalid_argument("IP family must be either AF_INET or AF_INET6");
}
}
uint16_t get_port(const struct sockaddr* sa) {
if (!sa) throw std::invalid_argument("socket pointer is null");
if (sa->sa_family == AF_INET) {
return (reinterpret_cast(sa))->sin_port;
} else if (sa->sa_family == AF_INET6) {
return (reinterpret_cast(sa))->sin6_port;
} else {
throw std::invalid_argument("IP family must be either AF_INET or AF_INET6");
}
}
size_t http_unescape(std::string* val) {
if (val->empty()) return 0;
unsigned int rpos = 0;
unsigned int wpos = 0;
unsigned int num;
unsigned int size = val->size();
while (rpos < size && (*val)[rpos] != '\0') {
switch ((*val)[rpos]) {
case '+':
(*val)[wpos] = ' ';
wpos++;
rpos++;
break;
case '%':
if (size > rpos + 2 && ((1 == sscanf(val->substr(rpos + 1, 2).c_str(), "%2x", &num)) || (1 == sscanf(val->substr(rpos + 1, 2).c_str(), "%2X", &num)))) {
(*val)[wpos] = (unsigned char) num;
wpos++;
rpos += 3;
break;
}
// intentional fall through!
default:
(*val)[wpos] = (*val)[rpos];
wpos++;
rpos++;
}
}
(*val)[wpos] = '\0'; // add 0-terminator
val->resize(wpos);
return wpos; // = strlen(val)
}
ip_representation::ip_representation(const struct sockaddr* ip) {
std::fill(pieces, pieces + 16, 0);
if (ip->sa_family == AF_INET) {
ip_version = http_utils::IPV4;
const in_addr* sin_addr_pt = &((reinterpret_cast(ip))->sin_addr);
for (int i = 0; i < 4; i++) {
pieces[12 + i] = (reinterpret_cast(sin_addr_pt))[i];
}
} else {
ip_version = http_utils::IPV6;
const in6_addr* sin_addr6_pt = &((reinterpret_cast(ip))->sin6_addr);
for (int i = 0; i < 16; i++) {
pieces[i] = (reinterpret_cast(sin_addr6_pt))[i];
}
}
mask = DEFAULT_MASK_VALUE;
}
ip_representation::ip_representation(const std::string& ip) {
std::vector parts;
mask = DEFAULT_MASK_VALUE;
std::fill(pieces, pieces + 16, 0);
if (ip.find(':') != std::string::npos) { // IPV6
ip_version = http_utils::IPV6;
parts = string_utilities::string_split(ip, ':', false);
if (parts.size() > 8) {
throw std::invalid_argument("IP is badly formatted. Max 8 parts in IPV6.");
}
unsigned int omitted = 8 - (parts.size() - 1);
if (omitted != 0) {
int empty_count = 0;
for (unsigned int i = 0; i < parts.size(); i++) {
if (parts[i].size() == 0) empty_count++;
}
if (empty_count > 1) {
if (parts[parts.size() - 1].find(".") != std::string::npos) omitted -= 1;
if (empty_count == 2 && parts[0] == "" && parts[1] == "") {
omitted += 1;
parts = std::vector(parts.begin() + 1, parts.end());
} else {
throw std::invalid_argument("IP is badly formatted. Cannot have more than one omitted segment in IPV6.");
}
}
}
int y = 0;
for (unsigned int i = 0; i < parts.size(); i++) {
if (parts[i] != "*") {
if (parts[i].size() == 0) {
for (unsigned int omitted_idx = 0; omitted_idx < omitted; omitted_idx++) {
pieces[y] = 0;
pieces[y+1] = 0;
y += 2;
}
continue;
}
if (parts[i].size() < 4) {
std::stringstream ss;
ss