| 4965 | } |
| 4966 | |
| 4967 | inline bool Server::parse_request_line(const char *s, Request &req) { |
| 4968 | auto len = strlen(s); |
| 4969 | if (len < 2 || s[len - 2] != '\r' || s[len - 1] != '\n') { return false; } |
| 4970 | len -= 2; |
| 4971 | |
| 4972 | { |
| 4973 | size_t count = 0; |
| 4974 | |
| 4975 | detail::split(s, s + len, ' ', [&](const char *b, const char *e) { |
| 4976 | switch (count) { |
| 4977 | case 0: req.method = std::string(b, e); break; |
| 4978 | case 1: req.target = std::string(b, e); break; |
| 4979 | case 2: req.version = std::string(b, e); break; |
| 4980 | default: break; |
| 4981 | } |
| 4982 | count++; |
| 4983 | }); |
| 4984 | |
| 4985 | if (count != 3) { return false; } |
| 4986 | } |
| 4987 | |
| 4988 | static const std::set<std::string> methods{ |
| 4989 | "GET", "HEAD", "POST", "PUT", "DELETE", |
| 4990 | "CONNECT", "OPTIONS", "TRACE", "PATCH", "PRI"}; |
| 4991 | |
| 4992 | if (methods.find(req.method) == methods.end()) { return false; } |
| 4993 | |
| 4994 | if (req.version != "HTTP/1.1" && req.version != "HTTP/1.0") { return false; } |
| 4995 | |
| 4996 | { |
| 4997 | // Skip URL fragment |
| 4998 | for (size_t i = 0; i < req.target.size(); i++) { |
| 4999 | if (req.target[i] == '#') { |
| 5000 | req.target.erase(i); |
| 5001 | break; |
| 5002 | } |
| 5003 | } |
| 5004 | |
| 5005 | size_t count = 0; |
| 5006 | |
| 5007 | detail::split(req.target.data(), req.target.data() + req.target.size(), '?', |
| 5008 | [&](const char *b, const char *e) { |
| 5009 | switch (count) { |
| 5010 | case 0: |
| 5011 | req.path = detail::decode_url(std::string(b, e), false); |
| 5012 | break; |
| 5013 | case 1: { |
| 5014 | if (e - b > 0) { |
| 5015 | detail::parse_query_text(std::string(b, e), req.params); |
| 5016 | } |
| 5017 | break; |
| 5018 | } |
| 5019 | default: break; |
| 5020 | } |
| 5021 | count++; |
| 5022 | }); |
| 5023 | |
| 5024 | if (count > 2) { return false; } |
nothing calls this directly
no test coverage detected