//// Copyright (c) 2023 Ruben Perez Hidalgo (rubenperez038 at gmail dot com)//// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//#include "util/cookie.hpp"#include <sstream>#include <stdexcept>#include <string_view>#include "error.hpp"using namespace chat;// Copied from Boost.Beast. Returns whether a character is valid in the context// of a HTTP token (RFC2616/RFC7230). Cookie names must be valid HTTP tokens.static bool is_token_char(char c) noexcept{/*tchar = "!" | "#" | "$" | "%" | "&" |"'" | "*" | "+" | "-" | "." |"^" | "_" | "`" | "|" | "~" |DIGIT | ALPHA*/static char constexpr tab[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 321, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 480, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 641, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 801, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 961, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240};static_assert(sizeof(tab) == 256u);return tab[static_cast<unsigned char>(c)];}// Returns whether a character is valid in the context of a cookie value.// See https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.1static bool is_cookie_value_char(char c) noexcept{// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E// ; US-ASCII characters excluding CTLs,// ; whitespace DQUOTE, comma, semicolon,// ; and backslashstatic char constexpr tab[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 321, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, // 481, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 641, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 801, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 961, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 1120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1440, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1600, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1760, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2080, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240};static_assert(sizeof(tab) == 256u);return tab[static_cast<unsigned char>(c)];}// Skips optional whitespacestatic const char* skip_ows(const char* it, const char* end) noexcept{while (it != end && (*it == ' ' || *it == '\t'))++it;return it;}// Skips a tokenstatic const char* skip_token(const char* it, const char* last) noexcept{while (it != last && is_token_char(*it))++it;return it;}// Skips a cookie valuestatic const char* skip_cookie_value(const char* it, const char* last) noexcept{while (it != last && is_cookie_value_char(*it))++it;return it;}static bool is_valid_token(std::string_view value) noexcept{if (value.empty())return false;for (char c : value){if (!is_token_char(c))return false;}return true;}static bool is_valid_cookie_value(std::string_view value) noexcept{if (value.empty())return false;for (char c : value){if (!is_cookie_value_char(c))return false;}return true;}static std::string_view trim_ows(std::string_view from) noexcept{const char* first = from.data();const char* last = from.data() + from.size();first = skip_ows(first, last);return std::string_view(first, last - first);}set_cookie_builder::set_cookie_builder(std::string_view name, std::string_view value): name_(name), value_(value){if (!is_valid_token(name_))throw std::invalid_argument("Invalid cookie name");if (!is_valid_cookie_value(value_))throw std::invalid_argument("Invalid cookie value");}std::string set_cookie_builder::build_header() const{std::ostringstream oss;oss << name_ << '=' << value_;if (http_only_)oss << "; HttpOnly";if (max_age_)oss << "; Max-Age=" << max_age_->count();if (same_site_ != same_site_t::lax)oss << "; SameSite=" << (same_site_ == same_site_t::none ? "None" : "Strict");if (secure_)oss << "; Secure";return oss.str();}// Grammar for the Cookie header// https://datatracker.ietf.org/doc/html/rfc6265//// cookie-header = "Cookie:" OWS cookie-string OWS// cookie-string = cookie-pair *( ";" SP cookie-pair )// cookie-pair = cookie-name "=" cookie-value// cookie-name = token// cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )// cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E// ; US-ASCII characters excluding CTLs,// ; whitespace DQUOTE, comma, semicolon,// ; and backslash// Trim the initial OWS. The final OWS can be left there, since when no more cookies// are found, increment() sets the iterator to end()cookie_list::cookie_list(std::string_view header) noexcept : header_(trim_ows(header)) {}void cookie_list::const_iterator::increment(bool is_first) noexcept{// Check that this is not a sentinel iteratorassert(next_ != nullptr);assert(last_ != nullptr);const char* current = next_;const char* const last = last_;// If we're parsing subsequent cookies, skip a semicolon and a spaceif (!is_first){if (current == last || *current++ != ';')return reset();if (current == last || *current++ != ' ')return reset();}// Cookie name. Empty cookie names are not validauto name_first = current;current = skip_token(current, last);std::string_view name(name_first, current - name_first);if (name.empty())return reset();// Equal signif (current == last || *current++ != '=')return reset();// Cookie value. Note that quotes are part of the valueauto value_first = current;bool is_quoted = false;if (current != last && *current == '"'){++current;is_quoted = true;}current = skip_cookie_value(current, last);if (is_quoted){if (current == last || *current != '"')return reset();++current;}std::string_view value(value_first, current - value_first);// Done parsingval_.name = name;val_.value = value;next_ = current;last_ = last;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。