120 lines
3.0 KiB
C++
120 lines
3.0 KiB
C++
// https://github.com/mfichman/http
|
|
|
|
#include "Http.hpp"
|
|
|
|
#include <cassert>
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
#include "Socket.hpp"
|
|
#include "SecureSocket.hpp"
|
|
|
|
#undef DELETE
|
|
|
|
namespace std::net
|
|
{
|
|
Response Http::Send(Request const& request)
|
|
{
|
|
// Send an HTTP request. Auto-fill the content-length headers.
|
|
std::string string = Str(request);
|
|
|
|
uint16_t port = 0;
|
|
std::unique_ptr<Socket> socket;
|
|
std::unique_ptr<SecureSocket> secure_socket;
|
|
bool secure = false;
|
|
if (request.GetUri().GetScheme() == "https")
|
|
{
|
|
secure_socket.reset(new SecureSocket());
|
|
port = 443;
|
|
secure = true;
|
|
}
|
|
else if (request.GetUri().GetScheme() == "http")
|
|
{
|
|
socket.reset(new Socket(SocketType::Streaming));
|
|
port = 80;
|
|
}
|
|
else
|
|
assert(!"unknown http scheme");
|
|
|
|
if (request.GetUri().GetPort())
|
|
port = request.GetUri().GetPort();
|
|
|
|
secure ? secure_socket->Connect(IPAddress(request.GetUri().GetHost(), port)) : socket->Connect(IPAddress(request.GetUri().GetHost(), port));
|
|
int32_t sent;
|
|
secure ? secure_socket->Recv((uint8_t*)string.c_str(), string.size(), sent) : socket->Send((uint8_t*)string.c_str(), string.size(), sent);
|
|
|
|
std::vector<char> buffer(16384); // 16 KiB
|
|
std::stringstream ss;
|
|
|
|
int32_t read;
|
|
do
|
|
{
|
|
secure ? secure_socket->Recv((uint8_t*)&buffer[0], buffer.size(), read) : socket->Recv((uint8_t*)&buffer[0], buffer.size(), read);
|
|
ss.write(&buffer[0], read);
|
|
}
|
|
while (read > 0);
|
|
secure ? secure_socket->Close() : socket->Close();
|
|
|
|
return Response(ss.str());
|
|
}
|
|
|
|
Response Http::Get(std::string const& path, std::string const& data)
|
|
{
|
|
// Shortcut for simple GET requests
|
|
Request request;
|
|
request.SetMethod(Method::GET);
|
|
request.SetUri(Uri(path));
|
|
request.SetData(data);
|
|
return Send(request);
|
|
}
|
|
|
|
Response Http::Post(std::string const& path, std::string const& data)
|
|
{
|
|
// Shortcut for simple POST requests
|
|
Request request;
|
|
request.SetMethod(Method::POST);
|
|
request.SetUri(Uri(path));
|
|
request.SetData(data);
|
|
return Send(request);
|
|
}
|
|
|
|
static std::string str_impl(Method method) {
|
|
switch (method)
|
|
{
|
|
case Method::GET:
|
|
return "GET";
|
|
case Method::HEAD:
|
|
return "HEAD";
|
|
case Method::POST:
|
|
return "POST";
|
|
case Method::PUT:
|
|
return "PUT";
|
|
case Method::DELETE:
|
|
return "DELETE";
|
|
case Method::TRACE:
|
|
return "TRACE";
|
|
case Method::CONNECT:
|
|
return "CONNECT";
|
|
default:
|
|
assert(!"unknown request method");
|
|
}
|
|
return "";
|
|
}
|
|
|
|
std::string Http::Str(Request const& request)
|
|
{
|
|
// Serialize a request to a string
|
|
std::stringstream ss;
|
|
auto path = request.GetPath().empty() ? "/" : request.GetPath();
|
|
ss << str_impl(request.GetMethod()) << ' ' << path << " HTTP/1.1\n";
|
|
ss << Headers::HOST << ": " << request.GetUri().GetHost() << "\n";
|
|
ss << Headers::CONTENT_LENGTH << ": " << request.GetData().size() << "\n";
|
|
ss << Headers::CONNECTION << ": close\n";
|
|
ss << Headers::ACCEPT_ENCODING << ": identity\n";
|
|
for (auto header : request.GetHeaders())
|
|
ss << header.first << ": " << header.second << "\n";
|
|
ss << "\n";
|
|
ss << request.GetData();
|
|
return ss.str();
|
|
}
|
|
} |