| 4020 | bool is_valid() const { return is_valid_; } |
| 4021 | |
| 4022 | bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, |
| 4023 | const MultipartContentHeader &header_callback) { |
| 4024 | |
| 4025 | // TODO: support 'filename*' |
| 4026 | static const std::regex re_content_disposition( |
| 4027 | R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~", |
| 4028 | std::regex_constants::icase); |
| 4029 | |
| 4030 | buf_append(buf, n); |
| 4031 | |
| 4032 | while (buf_size() > 0) { |
| 4033 | switch (state_) { |
| 4034 | case 0: { // Initial boundary |
| 4035 | buf_erase(buf_find(dash_boundary_crlf_)); |
| 4036 | if (dash_boundary_crlf_.size() > buf_size()) { return true; } |
| 4037 | if (!buf_start_with(dash_boundary_crlf_)) { return false; } |
| 4038 | buf_erase(dash_boundary_crlf_.size()); |
| 4039 | state_ = 1; |
| 4040 | break; |
| 4041 | } |
| 4042 | case 1: { // New entry |
| 4043 | clear_file_info(); |
| 4044 | state_ = 2; |
| 4045 | break; |
| 4046 | } |
| 4047 | case 2: { // Headers |
| 4048 | auto pos = buf_find(crlf_); |
| 4049 | if (pos > CPPHTTPLIB_HEADER_MAX_LENGTH) { return false; } |
| 4050 | while (pos < buf_size()) { |
| 4051 | // Empty line |
| 4052 | if (pos == 0) { |
| 4053 | if (!header_callback(file_)) { |
| 4054 | is_valid_ = false; |
| 4055 | return false; |
| 4056 | } |
| 4057 | buf_erase(crlf_.size()); |
| 4058 | state_ = 3; |
| 4059 | break; |
| 4060 | } |
| 4061 | |
| 4062 | static const std::string header_name = "content-type:"; |
| 4063 | const auto header = buf_head(pos); |
| 4064 | if (start_with_case_ignore(header, header_name)) { |
| 4065 | file_.content_type = trim_copy(header.substr(header_name.size())); |
| 4066 | } else { |
| 4067 | std::smatch m; |
| 4068 | if (std::regex_match(header, m, re_content_disposition)) { |
| 4069 | file_.name = m[1]; |
| 4070 | file_.filename = m[2]; |
| 4071 | } else { |
| 4072 | is_valid_ = false; |
| 4073 | return false; |
| 4074 | } |
| 4075 | } |
| 4076 | buf_erase(pos + crlf_.size()); |
| 4077 | pos = buf_find(crlf_); |
| 4078 | } |
| 4079 | if (state_ != 3) { return true; } |
no test coverage detected