| 3725 | |
| 3726 | #ifdef CPPHTTPLIB_NO_EXCEPTIONS |
| 3727 | inline bool parse_range_header(const std::string &s, Ranges &ranges) { |
| 3728 | #else |
| 3729 | inline bool parse_range_header(const std::string &s, Ranges &ranges) try { |
| 3730 | #endif |
| 3731 | static auto re_first_range = std::regex(R"(bytes=(\d*-\d*(?:,\s*\d*-\d*)*))"); |
| 3732 | std::smatch m; |
| 3733 | if (std::regex_match(s, m, re_first_range)) { |
| 3734 | auto pos = static_cast<size_t>(m.position(1)); |
| 3735 | auto len = static_cast<size_t>(m.length(1)); |
| 3736 | bool all_valid_ranges = true; |
| 3737 | split(&s[pos], &s[pos + len], ',', [&](const char *b, const char *e) { |
| 3738 | if (!all_valid_ranges) return; |
| 3739 | static auto re_another_range = std::regex(R"(\s*(\d*)-(\d*))"); |
| 3740 | std::cmatch cm; |
| 3741 | if (std::regex_match(b, e, cm, re_another_range)) { |
| 3742 | ssize_t first = -1; |
| 3743 | if (!cm.str(1).empty()) { |
| 3744 | first = static_cast<ssize_t>(std::stoll(cm.str(1))); |
| 3745 | } |
| 3746 | |
| 3747 | ssize_t last = -1; |
| 3748 | if (!cm.str(2).empty()) { |
| 3749 | last = static_cast<ssize_t>(std::stoll(cm.str(2))); |
| 3750 | } |
| 3751 | |
| 3752 | if (first != -1 && last != -1 && first > last) { |
| 3753 | all_valid_ranges = false; |
| 3754 | return; |
| 3755 | } |
| 3756 | ranges.emplace_back(std::make_pair(first, last)); |
| 3757 | } |
| 3758 | }); |
| 3759 | return all_valid_ranges; |
| 3760 | } |
| 3761 | return false; |
| 3762 | #ifdef CPPHTTPLIB_NO_EXCEPTIONS |
| 3763 | } |
| 3764 | #else |
| 3765 | } catch (...) { return false; } |
| 3766 | #endif |
| 3767 | |
| 3768 | class MultipartFormDataParser { |
| 3769 | public: |
| 3770 | MultipartFormDataParser() = default; |
| 3771 | |
| 3772 | void set_boundary(std::string &&boundary) { boundary_ = boundary; } |
| 3773 | |
| 3774 | bool is_valid() const { return is_valid_; } |
| 3775 | |
| 3776 | bool parse(const char *buf, size_t n, const ContentReceiver &content_callback, |
| 3777 | const MultipartContentHeader &header_callback) { |
| 3778 | |
| 3779 | // TODO: support 'filename*' |
| 3780 | static const std::regex re_content_disposition( |
| 3781 | R"~(^Content-Disposition:\s*form-data;\s*name="(.*?)"(?:;\s*filename="(.*?)")?(?:;\s*filename\*=\S+)?\s*$)~", |
| 3782 | std::regex_constants::icase); |
| 3783 | |
| 3784 | static const std::string dash_ = "--"; |
no test coverage detected