include/ylt/standalone/cinatra/coro_http_request.hpp (255 lines of code) (raw):

#pragma once #include <any> #include <charconv> #include <initializer_list> #include <optional> #include <regex> #include <string> #include "async_simple/coro/Lazy.h" #include "define.h" #include "http_parser.hpp" #include "session.hpp" #include "session_manager.hpp" #include "utils.hpp" #include "ws_define.h" namespace cinatra { inline std::vector<std::pair<int, int>> parse_ranges(std::string_view range_str, size_t file_size, bool &is_valid) { range_str = trim_sv(range_str); if (range_str.empty()) { return {{0, file_size - 1}}; } if (range_str.find("--") != std::string_view::npos) { is_valid = false; return {}; } if (range_str == "-") { return {{0, file_size - 1}}; } std::vector<std::pair<int, int>> vec; auto ranges = split_sv(range_str, ","); for (auto range : ranges) { auto sub_range = split_sv(range, "-"); auto fist_range = trim_sv(sub_range[0]); int start = 0; if (fist_range.empty()) { start = -1; } else { auto [ptr, ec] = std::from_chars( fist_range.data(), fist_range.data() + fist_range.size(), start); if (ec != std::errc{}) { is_valid = false; return {}; } } int end = 0; if (sub_range.size() == 1) { end = file_size - 1; } else { auto second_range = trim_sv(sub_range[1]); if (second_range.empty()) { end = file_size - 1; } else { auto [ptr, ec] = std::from_chars(second_range.data(), second_range.data() + second_range.size(), end); if (ec != std::errc{}) { is_valid = false; return {}; } } } if (start > 0 && (start >= file_size || start == end)) { // out of range is_valid = false; return {}; } if (end > 0 && end >= file_size) { end = file_size - 1; } if (start == -1) { start = file_size - end; end = file_size - 1; } vec.push_back({start, end}); } return vec; } class coro_http_connection; class coro_http_request { public: coro_http_request(http_parser &parser, coro_http_connection *conn) : parser_(parser), conn_(conn) {} std::string_view get_header_value(std::string_view key) { auto headers = parser_.get_headers(); for (auto &header : headers) { if (iequal0(header.name, key)) { return header.value; } } return {}; } std::string_view get_query_value(std::string_view key) { return parser_.get_query_value(key); } std::string get_decode_query_value(std::string_view key) { auto value = parser_.get_query_value(key); if (value.empty()) { return ""; } return code_utils::get_string_by_urldecode(value); } std::span<http_header> get_headers() const { return parser_.get_headers(); } const auto &get_queries() const { return parser_.queries(); } std::string_view full_url() { return parser_.full_url(); } void set_body(std::string &body) { body_ = body; auto type = get_content_type(); if (type == content_type::urlencoded) { parser_.parse_query(body_); } } std::string_view get_body() const { return body_; } bool is_chunked() { return parser_.is_chunked(); } std::string_view get_accept_encoding() { return get_header_value("Accept-Encoding"); } content_encoding get_encoding_type() { auto encoding_type = get_header_value("Content-Encoding"); if (!encoding_type.empty()) { if (encoding_type.find("gzip") != std::string_view::npos) return content_encoding::gzip; else if (encoding_type.find("deflate") != std::string_view::npos) return content_encoding::deflate; else if (encoding_type.find("br") != std::string_view::npos) return content_encoding::br; else return content_encoding::none; } else { return content_encoding::none; } } content_type get_content_type() { if (is_chunked()) return content_type::chunked; auto content_type = get_header_value("content-type"); if (!content_type.empty()) { if (content_type.find("application/x-www-form-urlencoded") != std::string_view::npos) { return content_type::urlencoded; } else if (content_type.find("multipart/form-data") != std::string_view::npos) { return content_type::multipart; } else if (content_type.find("application/octet-stream") != std::string_view::npos) { return content_type::octet_stream; } else { return content_type::string; } } if (is_websocket_) { return content_type::websocket; } return content_type::unknown; } std::string_view get_url() { return parser_.url(); } std::string_view get_method() { return parser_.method(); } std::string_view get_boundary() { auto content_type = get_header_value("content-type"); if (content_type.empty()) { return {}; } auto pos = content_type.rfind("="); if (pos == std::string_view::npos) { return ""; } return content_type.substr(pos + 1); } coro_http_connection *get_conn() { return conn_; } bool is_upgrade() { if (!parser_.has_upgrade()) return false; auto u = get_header_value("Upgrade"); if (u.empty()) return false; if (u != WEBSOCKET) return false; auto sec_ws_key = get_header_value("sec-websocket-key"); if (sec_ws_key.empty() || sec_ws_key.size() != 24) return false; is_websocket_ = true; return true; } bool is_support_compressed() { auto extension_str = get_header_value("Sec-WebSocket-Extensions"); if (extension_str.find("permessage-deflate") != std::string::npos) { return true; } return false; } void set_aspect_data(std::vector<std::string> data) { aspect_data_ = std::move(data); } template <typename... Args> void set_aspect_data(Args... args) { (aspect_data_.push_back(std::move(args)), ...); } void set_user_data(std::any data) { user_data_ = std::move(data); } std::any get_user_data() { return user_data_; } std::vector<std::string> &get_aspect_data() { return aspect_data_; } std::unordered_map<std::string_view, std::string_view> get_cookies( std::string_view cookie_str) const { auto cookies = get_cookies_map(cookie_str); return cookies; } std::shared_ptr<session> get_session(bool create = true) { auto &session_manager = session_manager::get(); auto cookies = get_cookies(get_header_value("Cookie")); std::string session_id; auto iter = cookies.find(CSESSIONID); if (iter == cookies.end() && !create) { return nullptr; } else if (iter == cookies.end()) { session_id = session_manager.generate_session_id(); } else { session_id = iter->second; } cached_session_id_ = session_id; return session_manager.get_session(session_id); } std::string get_cached_session_id() { std::string temp_session_id = ""; cached_session_id_.swap(temp_session_id); return temp_session_id; } bool has_session() { return !cached_session_id_.empty(); } void clear() { body_ = {}; if (!aspect_data_.empty()) { aspect_data_.clear(); } if (user_data_.has_value()) { user_data_.reset(); } } std::unordered_map<std::string, std::string> params_; std::smatch matches_; private: http_parser &parser_; std::string_view body_; coro_http_connection *conn_; bool is_websocket_ = false; std::vector<std::string> aspect_data_; std::string cached_session_id_; std::any user_data_; }; } // namespace cinatra