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