Size: 3464 bytes.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
// cs/net/http/request.cc
#include "cs/net/http/request.hh"

#include <stdint.h>

#include <map>
#include <ostream>
#include <sstream>
#include <string>

#include "cs/net/http/parsers.hh"
#include "cs/result.hh"
#include "cs/util/string.hh"

namespace cs::net::http {

namespace {
using ::cs::Error;
using ::cs::NotFoundError;
using ::cs::Ok;
using ::cs::Result;
using ::cs::net::http::parsers::AtEndOfLine;
using ::cs::net::http::parsers::IncrementCursor;
using ::cs::net::http::parsers::ParsePath;
using ::cs::net::http::parsers::ReadThroughNewline;
using ::cs::net::http::parsers::ReadWord;
using ::cs::util::string::ToLowercase;
}  // namespace

Result Request::Parse(std::string str) {
  _str = str;
  unsigned int cursor = 0;
  // Read HTTP method
  OK_OR_RET(ReadWord(str, &cursor, &_method, " "));
  OK_OR_RET(IncrementCursor(str, &cursor));
  // Read HTTP path
  OK_OR_RET(ReadWord(str, &cursor, &_path, " "));
  OK_OR_RET(ParsePath(_path, &_path, &_query_params));
  OK_OR_RET(IncrementCursor(str, &cursor));
  // Read HTTP/1.1 tag
  std::string http_tag = "";
  OK_OR_RET(ReadWord(str, &cursor, &http_tag, "\n"));
  if (http_tag != "HTTP/1.1") {
    return TRACE(Error(
        "Didn't find HTTP/1.1 tag at end of first line."));
  }
  OK_OR_RET(IncrementCursor(str, &cursor));
  // Read headers
  bool reading_headers = true;
  while (reading_headers) {
    std::string name;
    OK_OR_RET(ReadWord(str, &cursor, &name, ":"));
    OK_OR_RET(IncrementCursor(str, &cursor));
    if (str.at(cursor) != ' ') {
      return TRACE(Error("Expected space after colon."));
    }
    OK_OR_RET(IncrementCursor(str, &cursor));
    std::string value;
    OK_OR_RET(ReadWord(str, &cursor, &value, "\n"));
    OK_OR_RET(ReadThroughNewline(str, &cursor));
    _headers[name] = value;
    if (AtEndOfLine(str, cursor).ok()) {
      reading_headers = false;
    }
  }
  OK_OR_RET(ReadThroughNewline(str, &cursor));
  // Read body
  _body = str.substr(cursor, str.length() - cursor);
  return Ok();
}

std::string Request::UrlDecode(const std::string& str) {
  std::ostringstream decoded;
  for (size_t i = 0; i < str.length(); ++i) {
    if (str[i] == '%') {
      if (i + 2 < str.length()) {
        int hexValue;
        std::istringstream hexStream(str.substr(i + 1, 2));
        hexStream >> std::hex >> hexValue;
        decoded << static_cast<char>(hexValue);
        i += 2;
      }
    } else if (str[i] == '+') {
      decoded << ' ';
    } else {
      decoded << str[i];
    }
  }
  return decoded.str();
}

std::map<std::string, std::string>
Request::ParseFormUrlEncoded(const std::string& body) {
  std::map<std::string, std::string> formData;
  std::istringstream ss(body);
  std::string pair;
  while (std::getline(ss, pair, '&')) {
    size_t equalPos = pair.find('=');
    if (equalPos != std::string::npos) {
      std::string key = UrlDecode(pair.substr(0, equalPos));
      std::string value =
          UrlDecode(pair.substr(equalPos + 1));
      formData[key] = value;
    }
  }
  return formData;
}

cs::ResultOr<std::string> Request::NormalizedHost() const {
  for (const auto& [name, value] : _headers) {
    if (ToLowercase(name) == "host") {
      std::string host = ToLowercase(value);
      std::string::size_type colon = host.find(':');
      if (colon != std::string::npos) {
        host = host.substr(0, colon);
      }
      return host;
    }
  }
  return TRACE(NotFoundError("Host header missing."));
}

}  // namespace cs::net::http
v0 (commit) © 2025 @p13i.io | Load balancer proxied to: cs-code-viewer-2:8080 in 5ms.