#include "response.h"
#define ERR(error) std::unexpected(error)
+#define NEW_LINE "\r\n"
namespace http {
- std::expected<Response, Error> send(Method, const RequestOpts& req);
+ std::expected<Response, Error> sendreq(Method, const RequestOpts& req);
std::expected<int8_t, Error> connect_to(const std::string& domain_name, const uint16_t port = 80);
} // namespace http
#include "http.h"
int main() {
- auto resp1 = http::send(http::Method::GET, {.domain_name = "google.com"});
- resp1 = http::send(http::Method::GET, {.domain_name = "example.com", .port = 0});
+ auto resp1 = http::sendreq(http::Method::GET, {.domain_name = "example.com"});
+ // auto resp1 = http::sendreq(http::Method::POST, {.domain_name = "example.com", .body = "Hello, World!"});
if (!resp1.has_value()) {
switch (resp1.error()) {
--- /dev/null
+#include "method.h"
+
+std::ostream &operator<<(std::ostream &os, const http::Method &method) {
+ using namespace http;
+
+ switch (method) {
+ case Method::GET: {
+ return os << "GET";
+ } break;
+ case Method::HEAD: {
+ return os << "HEAD";
+ } break;
+ case Method::POST: {
+ return os << "POST";
+ } break;
+ case Method::PUT: {
+ return os << "PUT";
+ } break;
+ case Method::DELETE: {
+ return os << "DELETE";
+ } break;
+ case Method::CONNECT: {
+ return os << "CONNECT";
+ } break;
+ case Method::OPTIONS: {
+ return os << "OPTIONS";
+ } break;
+ case Method::TRACE: {
+ return os << "TRACE";
+ } break;
+ case Method::PATCH: {
+ return os << "PATCH";
+ } break;
+ case Method::UPDATE: {
+ return os << "UPDATE";
+ } break;
+ }
+}
namespace http {
struct RequestOpts {
- const std::string domain_name;
- const uint16_t port = 80;
- const std::string path = "/";
- const std::string body = "";
+ uint16_t port = 80;
+ std::string domain_name;
+ std::string host = domain_name;
+ std::string query = "/";
+ std::string accept = "*/*";
+ std::string body = "";
+
+ struct {
+ uint8_t major = 1;
+ uint8_t minor = 1;
+ } http_version;
};
-}
+} // namespace http
-#include <chrono>
#include <iostream>
+#include <sstream>
#include <unordered_map>
#include "http.h"
+#define BUFFSIZE 1024
+
static std::unordered_map<std::string, struct addrinfo> ip_map;
namespace http {
return remote_socketfd;
}
- std::expected<Response, Error> send(Method method, const RequestOpts &req) {
- auto start = std::chrono::system_clock::now();
+ std::expected<Response, Error> sendreq(Method method, const RequestOpts &req) {
auto maybe_socketfd = connect_to(req.domain_name, req.port);
- auto end = std::chrono::system_clock::now();
-
- std::chrono::duration<double> elapsed_seconds = end - start;
- std::cout << "elapsed time: " << elapsed_seconds.count() << "s\t";
if (!maybe_socketfd.has_value()) {
return ERR(maybe_socketfd.error());
}
- std::cout << "All good" << std::endl;
+ std::stringstream ss;
+ ss << method << " " << req.query << " HTTP/" << (int)req.http_version.major << "."
+ << (int)req.http_version.minor << NEW_LINE;
+ ss << "Host: " << req.host << NEW_LINE;
+ ss << "Accept: " << req.accept << NEW_LINE;
+
+ if (!req.body.empty()) {
+ ss << "Content-Length: " << req.body.length() << NEW_LINE << NEW_LINE << req.body;
+ } else {
+ ss << NEW_LINE;
+ }
+
+ std::string msg = ss.str();
+ std::cout << "Request:\n===================\n" << msg << "\n===================\n" << std::endl;
+ send((int)maybe_socketfd.value(), msg.c_str(), msg.size(), 0);
+
+ msg = "";
+ char buffer[BUFFSIZE] = "";
+ ssize_t bytes_read = 0;
+ while ((bytes_read = read((int)maybe_socketfd.value(), buffer, BUFFSIZE - 1)) > 0) {
+ if (bytes_read == -1) {
+ std::cerr << "\t\tError while reading!" << std::endl;
+ }
+
+ buffer[bytes_read] = '\0';
+ msg += buffer;
+ }
+
+ std::cout << "Response:\n===================\n" << msg << "\n===================" << std::endl;
+
close(maybe_socketfd.value());
return Response();
}