| 5367 | } |
| 5368 | |
| 5369 | inline bool Server::parse_request_line(const char *s, Request &req) { |
| 5370 | auto len = strlen(s); |
| 5371 | if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; } |
| 5372 | len -= 2; |
| 5373 | |
| 5374 | { |
| 5375 | size_t count = 0; |
| 5376 | |
| 5377 | detail::split(s, s + len, ' ', [&](const char *b, const char *e) { |
| 5378 | switch (count) { |
| 5379 | case 0: req.method = std::string(b, e); break; |
| 5380 | case 1: req.target = std::string(b, e); break; |
| 5381 | case 2: req.version = std::string(b, e); break; |
| 5382 | default: break; |
| 5383 | } |
| 5384 | count++; |
| 5385 | }); |
| 5386 | |
| 5387 | if (count != 3) { return false; } |
| 5388 | } |
| 5389 | |
| 5390 | static const std::set<std::string> methods{ |
| 5391 | "GET", "HEAD", "POST", "PUT", "DELETE", |
| 5392 | "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; |
| 5393 | |
| 5394 | if (methods.find(req.method) == methods.end()) { return false; } |
| 5395 | |
| 5396 | if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } |
| 5397 | |
| 5398 | { |
| 5399 | // Skip URL fragment |
| 5400 | for (size_t i = 0; i < req.target.size(); i++) { |
| 5401 | if (req.target[i] == '#') { |
| 5402 | req.target.erase(i); |
| 5403 | break; |
| 5404 | } |
| 5405 | } |
| 5406 | |
| 5407 | size_t count = 0; |
| 5408 | |
| 5409 | detail::split(req.target.data(), req.target.data() + req.target.size(), '?', |
| 5410 | [&](const char *b, const char *e) { |
| 5411 | switch (count) { |
| 5412 | case 0: |
| 5413 | req.path = detail::decode_url(std::string(b, e), false); |
| 5414 | break; |
| 5415 | case 1: { |
| 5416 | if (e - b > 0) { |
| 5417 | detail::parse_query_text(std::string(b, e), req.params); |
| 5418 | } |
| 5419 | break; |
| 5420 | } |
| 5421 | default: break; |
| 5422 | } |
| 5423 | count++; |
| 5424 | }); |
| 5425 | |
| 5426 | if (count > 2) { return false; } |
nothing calls this directly
no test coverage detected