]> git.leonardobizzoni.com Git - http-lib/commitdiff
Send formatted HTTP req and receive raw HTTP response
authorLeonardoBizzoni <leo2002714@gmail.com>
Tue, 6 Aug 2024 14:48:56 +0000 (16:48 +0200)
committerLeonardoBizzoni <leo2002714@gmail.com>
Tue, 6 Aug 2024 14:48:56 +0000 (16:48 +0200)
.gitignore [new file with mode: 0644]
shell.nix
src/http.h
src/main.cpp
src/method.cpp [new file with mode: 0644]
src/method.h
src/request.h
src/send.cpp

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..90efbf4
--- /dev/null
@@ -0,0 +1,4 @@
+build
+bin
+.envrc
+.cache
\ No newline at end of file
index 5c24fb8f6deb33237136a951a58c72bf523f1c9f..334e56badf6db8cb584e77544876b3a485a78dfb 100644 (file)
--- a/shell.nix
+++ b/shell.nix
@@ -4,6 +4,7 @@ pkgs.mkShell {
   nativeBuildInputs = with pkgs; [
     man-pages
 
+    valgrind
     gnumake
     cmake
     clang-tools
index 5ba6b7489bdfd7e0d43f2d028735788984130332..8219975aab91d45ec6f0745d59113939758fbdcd 100644 (file)
 #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
index cf38174eb96034d6b58082e891831a2680b467ba..24f0f2113de6be3201957471afa7a1254b9b62cc 100644 (file)
@@ -3,8 +3,8 @@
 #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()) {
diff --git a/src/method.cpp b/src/method.cpp
new file mode 100644 (file)
index 0000000..afd1ac6
--- /dev/null
@@ -0,0 +1,38 @@
+#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;
+  }
+}
index df21a81c7d9989e0cf4f4818cbf7e351306ce436..3b787c1da70df5b03cb48c8950fd936f83152c45 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
+#include <ostream>
 namespace http {
   enum class Method {
     GET,
@@ -13,4 +14,6 @@ namespace http {
     PATCH,
     UPDATE,
   };
-}
+}  // namespace http
+
+std::ostream &operator<<(std::ostream &os, const http::Method &method);
index 76d80cffc69c7a8de95fb7aeba973a8026c61393..284ab9553584efc21917563ab9ce7b3e2a8721be 100644 (file)
@@ -4,9 +4,16 @@
 
 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
index 8ec3c13f990c6f7491b5364c4b75f2c8087d3705..934cf0da865c337f1d2a9482dafc2aa871e9c219 100644 (file)
@@ -1,9 +1,11 @@
-#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 {
@@ -64,19 +66,43 @@ 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();
   }