@brief multipart/form-data request parser @return parts of multipart/form-data
| 12 | ///@brief multipart/form-data request parser |
| 13 | ///@return parts of multipart/form-data |
| 14 | std::map<std::string, MultipartPart> parse_multipart(const http::request<http::string_body>& req) { |
| 15 | std::map<std::string, MultipartPart> parts; |
| 16 | |
| 17 | // 1. Extract the boundary from the Content-Type header |
| 18 | std::string content_type_header = std::string(req[http::field::content_type]); |
| 19 | std::string boundary; |
| 20 | size_t boundary_pos = content_type_header.find("boundary="); |
| 21 | if (boundary_pos != std::string::npos) { |
| 22 | boundary = "--" + content_type_header.substr(boundary_pos + 9); |
| 23 | } |
| 24 | else { |
| 25 | throw std::runtime_error("Invalid multipart/form-data: boundary not found."); |
| 26 | } |
| 27 | |
| 28 | std::string_view body = req.body(); |
| 29 | size_t start_pos = 0; |
| 30 | |
| 31 | // 2. Use the boundary to split the request body |
| 32 | while ((start_pos = body.find(boundary, start_pos)) != std::string_view::npos) { |
| 33 | start_pos += boundary.length(); |
| 34 | if (body.substr(start_pos, 2) == "--") { |
| 35 | break; // boundary ended |
| 36 | } |
| 37 | start_pos += 2; // skip \r\n |
| 38 | |
| 39 | size_t end_pos = body.find(boundary, start_pos); |
| 40 | if (end_pos == std::string_view::npos) { |
| 41 | break; |
| 42 | } |
| 43 | |
| 44 | std::string_view part_data = body.substr(start_pos, end_pos - start_pos - 2); // 减去 \r\n |
| 45 | |
| 46 | // 3. Parse each part |
| 47 | size_t headers_end_pos = part_data.find("\r\n\r\n"); |
| 48 | if (headers_end_pos == std::string_view::npos) { |
| 49 | continue; |
| 50 | } |
| 51 | |
| 52 | std::string_view headers_sv = part_data.substr(0, headers_end_pos); |
| 53 | MultipartPart part; |
| 54 | part.content = std::string(part_data.substr(headers_end_pos + 4)); |
| 55 | |
| 56 | // Parse the headers (Content-Disposition) |
| 57 | size_t cd_pos = headers_sv.find("Content-Disposition: form-data;"); |
| 58 | if (cd_pos != std::string_view::npos) { |
| 59 | size_t name_pos = headers_sv.find("name=\"", cd_pos); |
| 60 | if (name_pos != std::string_view::npos) { |
| 61 | name_pos += 6; |
| 62 | size_t name_end_pos = headers_sv.find("\"", name_pos); |
| 63 | part.name = std::string(headers_sv.substr(name_pos, name_end_pos - name_pos)); |
| 64 | } |
| 65 | |
| 66 | size_t filename_pos = headers_sv.find("filename=\"", cd_pos); |
| 67 | if (filename_pos != std::string_view::npos) { |
| 68 | filename_pos += 10; |
| 69 | size_t filename_end_pos = headers_sv.find("\"", filename_pos); |
| 70 | part.filename = std::string(headers_sv.substr(filename_pos, filename_end_pos - filename_pos)); |
| 71 | } |
no test coverage detected