Skip to content

Commit d0b34e4

Browse files
authored
Merge branch 'main' into book
2 parents bd66e52 + 28a3459 commit d0b34e4

File tree

1 file changed

+1
-163
lines changed

1 file changed

+1
-163
lines changed

parser.cpp

+1-163
Original file line numberDiff line numberDiff line change
@@ -1,163 +1 @@
1-
#include <string>
2-
#include <string_view>
3-
#include <unordered_map>
4-
#include <optional>
5-
#include <stdexcept>
6-
#include <algorithm>
7-
#include <memory>
8-
9-
class HttpParserError : public std::runtime_error
10-
{
11-
using std::runtime_error::runtime_error;
12-
};
13-
14-
class HttpRequest final
15-
{
16-
public:
17-
using Headers = std::unordered_map<std::string, std::string, std::hash<std::string>, std::equal_to<>>;
18-
19-
private:
20-
std::string method_;
21-
std::string path_;
22-
std::string version_;
23-
Headers headers_;
24-
std::string body_;
25-
26-
public:
27-
// Use string_view for efficient read-only access
28-
[[nodiscard]] std::string_view method() const noexcept { return method_; }
29-
[[nodiscard]] std::string_view path() const noexcept { return path_; }
30-
[[nodiscard]] std::string_view version() const noexcept { return version_; }
31-
[[nodiscard]] const Headers &headers() const noexcept { return headers_; }
32-
[[nodiscard]] std::string_view body() const noexcept { return body_; }
33-
34-
// Friend declaration for the parser
35-
friend class HttpParser;
36-
};
37-
38-
class HttpParser final
39-
{
40-
public:
41-
// Use string_view for efficient parsing without copying
42-
[[nodiscard]] std::optional<HttpRequest> parse(std::string_view raw_request) const
43-
{
44-
try
45-
{
46-
return parse_impl(raw_request);
47-
}
48-
catch (const std::exception &)
49-
{
50-
return std::nullopt;
51-
}
52-
}
53-
54-
private:
55-
[[nodiscard]] HttpRequest parse_impl(std::string_view raw_request) const
56-
{
57-
HttpRequest request;
58-
size_t pos = 0;
59-
size_t end_pos;
60-
61-
// Parse request line
62-
if ((end_pos = raw_request.find("\r\n", pos)) == std::string_view::npos)
63-
{
64-
throw HttpParserError("Invalid request line");
65-
}
66-
parse_request_line(raw_request.substr(pos, end_pos - pos), request);
67-
pos = end_pos + 2;
68-
69-
// Parse headers
70-
while (pos < raw_request.size())
71-
{
72-
end_pos = raw_request.find("\r\n", pos);
73-
if (end_pos == std::string_view::npos)
74-
{
75-
throw HttpParserError("Invalid header format");
76-
}
77-
78-
// Check for end of headers
79-
if (pos == end_pos)
80-
{
81-
pos += 2;
82-
break;
83-
}
84-
85-
parse_header(raw_request.substr(pos, end_pos - pos), request);
86-
pos = end_pos + 2;
87-
}
88-
89-
// Parse body
90-
if (pos < raw_request.size())
91-
{
92-
request.body_ = std::string(raw_request.substr(pos));
93-
}
94-
95-
return request;
96-
}
97-
98-
static void parse_request_line(std::string_view line, HttpRequest &request)
99-
{
100-
size_t method_end = line.find(' ');
101-
if (method_end == std::string_view::npos)
102-
{
103-
throw HttpParserError("Invalid request line format");
104-
}
105-
106-
size_t path_end = line.find(' ', method_end + 1);
107-
if (path_end == std::string_view::npos)
108-
{
109-
throw HttpParserError("Invalid request line format");
110-
}
111-
112-
request.method_ = std::string(line.substr(0, method_end));
113-
request.path_ = std::string(line.substr(method_end + 1, path_end - method_end - 1));
114-
request.version_ = std::string(line.substr(path_end + 1));
115-
116-
// Validate HTTP method
117-
if (!is_valid_method(request.method_))
118-
{
119-
throw HttpParserError("Invalid HTTP method");
120-
}
121-
}
122-
123-
static void parse_header(std::string_view line, HttpRequest &request)
124-
{
125-
size_t colon_pos = line.find(':');
126-
if (colon_pos == std::string_view::npos)
127-
{
128-
throw HttpParserError("Invalid header format");
129-
}
130-
131-
std::string_view key = line.substr(0, colon_pos);
132-
std::string_view value = line.substr(colon_pos + 1);
133-
134-
// Trim whitespace
135-
value = trim(value);
136-
137-
if (!key.empty() && !value.empty())
138-
{
139-
request.headers_.emplace(
140-
std::string(key),
141-
std::string(value));
142-
}
143-
}
144-
145-
[[nodiscard]] static std::string_view trim(std::string_view str) noexcept
146-
{
147-
const auto first = str.find_first_not_of(" \t\r\n");
148-
if (first == std::string_view::npos)
149-
return {};
150-
151-
const auto last = str.find_last_not_of(" \t\r\n");
152-
return str.substr(first, last - first + 1);
153-
}
154-
155-
[[nodiscard]] static bool is_valid_method(const std::string &method) noexcept
156-
{
157-
static const auto valid_methods = std::array{
158-
"GET", "POST", "PUT", "DELETE", "HEAD",
159-
"OPTIONS", "PATCH", "TRACE", "CONNECT"};
160-
161-
return std::find(valid_methods.begin(), valid_methods.end(), method) != valid_methods.end();
162-
}
163-
};
1+
#not implementesd

0 commit comments

Comments
 (0)