| 99 | } // namespace |
| 100 | |
| 101 | std::optional<std::string> extract_multipart_boundary(const std::string & content_type) { |
| 102 | const std::string lowered = lower_ascii(content_type); |
| 103 | if (lowered.rfind("multipart/", 0) != 0) { |
| 104 | return std::nullopt; |
| 105 | } |
| 106 | const std::string key = "boundary="; |
| 107 | const auto pos = lowered.find(key); |
| 108 | if (pos == std::string::npos) { |
| 109 | return std::nullopt; |
| 110 | } |
| 111 | std::string value = content_type.substr(pos + key.size()); |
| 112 | const auto semicolon = value.find(';'); |
| 113 | if (semicolon != std::string::npos) { |
| 114 | value = value.substr(0, semicolon); |
| 115 | } |
| 116 | value = trim(value); |
| 117 | if (value.size() >= 2 && value.front() == '"' && value.back() == '"') { |
| 118 | value = value.substr(1, value.size() - 2); |
| 119 | } |
| 120 | if (value.empty()) { |
| 121 | return std::nullopt; |
| 122 | } |
| 123 | return value; |
| 124 | } |
| 125 | |
| 126 | std::vector<MultipartPart> parse_multipart_body(const std::string & body, const std::string & boundary) { |
| 127 | std::vector<MultipartPart> parts; |