libravatarserv/src/http.cpp

140 lines
3.8 KiB
C++

/* This file is part of libravatarserv.
* Copyright © 2018,2019 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include "libravatarserv.hpp"
using std::cout;
using std::cerr;
using std::endl;
using namespace http;
const Request http::parse_request(const string &request)
{
if (request.substr(0, 8) == "/favicon")
{
cout << "Status: 404 Not Found\n\n";
std::exit(1);
}
if (request.substr(0, 8) != "/avatar/" ||
request.find("..", 8) != std::string::npos)
{
cout << "Status: 400 Bad Request\n\n";
cerr << "Error: Invalid URL.\n";
std::exit(1);
}
int16_t size = 80;
string fallback;
string digest = request.substr(8);
std::transform(digest.begin(), digest.end(), digest.begin(), ::tolower);
std::size_t pos_digest = digest.find('?');
if (pos_digest != std::string::npos)
{
string answer;
{
answer = get_parameter(request, "s");
if (!answer.empty())
{
try
{
size = static_cast<int16_t>(std::stoul(answer));
} catch (const std::exception &) {}
}
else
{
answer = get_parameter(request, "size");
if (!answer.empty())
{
try
{
size = static_cast<int16_t>(std::stoul(answer));
} catch (const std::exception &) {}
}
}
if (size > 512)
{
size = 512;
}
else if (size <= 0)
{
size = 80;
}
}
{
answer = get_parameter(request, "d");
if (!answer.empty())
{
fallback = answer;
}
else
{
answer = get_parameter(request, "default");
if (!answer.empty())
{
fallback = answer;
}
}
}
}
digest = digest.substr(0, pos_digest);
pos_digest = digest.find('.');
if (pos_digest != std::string::npos)
{
digest = digest.substr(0, pos_digest);
}
return { digest, size, fallback };
}
const string http::get_parameter(const string &request, const string &parameter)
{
std::size_t pos = request.find("&" + parameter + "=");
if (pos == std::string::npos)
{
pos = request.find("?" + parameter + "=");
}
if (pos != std::string::npos)
{
pos += (2 + parameter.length());
return request.substr(pos, request.find('&', pos));
}
return "";
}
void http::send_redirect(const Request &request)
{
const char *env = std::getenv("HTTPS");
string baseurl;
if (env != nullptr && env[1] == 'n')
{ // "on"
baseurl = "https://seccdn.libravatar.org";
}
else
{
baseurl = "http://cdn.libravatar.org";
}
cout << "Status: 307 Temporary Redirect\n";
cout << "Location: " << baseurl << "/avatar/"
<< request.digest << "?s=" << request.size
<< "&d=" << request.fallback << endl << endl;
}