1a8003a70SNiels Sascha Reedijk /* 2a8003a70SNiels Sascha Reedijk * Copyright 2022 Haiku Inc. All rights reserved. 3a8003a70SNiels Sascha Reedijk * Distributed under the terms of the MIT License. 4a8003a70SNiels Sascha Reedijk * 5a8003a70SNiels Sascha Reedijk * Authors: 6a8003a70SNiels Sascha Reedijk * Niels Sascha Reedijk, niels.reedijk@gmail.com 7a8003a70SNiels Sascha Reedijk */ 8a8003a70SNiels Sascha Reedijk 9a8003a70SNiels Sascha Reedijk #include <HttpFields.h> 10a8003a70SNiels Sascha Reedijk 11a8003a70SNiels Sascha Reedijk #include <algorithm> 12a8003a70SNiels Sascha Reedijk #include <ctype.h> 13a8003a70SNiels Sascha Reedijk #include <utility> 14a8003a70SNiels Sascha Reedijk 15cb67e348SNiels Sascha Reedijk #include "HttpPrivate.h" 16cb67e348SNiels Sascha Reedijk 17a8003a70SNiels Sascha Reedijk using namespace BPrivate::Network; 18a8003a70SNiels Sascha Reedijk 19a8003a70SNiels Sascha Reedijk 20a8003a70SNiels Sascha Reedijk // #pragma mark -- utilities 21a8003a70SNiels Sascha Reedijk 22a8003a70SNiels Sascha Reedijk 23a8003a70SNiels Sascha Reedijk /*! 24a8003a70SNiels Sascha Reedijk \brief Validate whether the string is a valid HTTP header value 25a8003a70SNiels Sascha Reedijk 26a8003a70SNiels Sascha Reedijk RFC 7230 section 3.2.6 determines that valid tokens for the header are: 27a8003a70SNiels Sascha Reedijk HTAB ('\t'), SP (32), all visible ASCII characters (33-126), and all characters that 28a8003a70SNiels Sascha Reedijk not control characters (in the case of a char, any value < 0) 29a8003a70SNiels Sascha Reedijk 30a8003a70SNiels Sascha Reedijk \note When printing out the HTTP header, sometimes the string needs to be quoted and some 31a8003a70SNiels Sascha Reedijk characters need to be escaped. This function is not checking for whether the string can 32a8003a70SNiels Sascha Reedijk be transmitted as is. 33a8003a70SNiels Sascha Reedijk 34a8003a70SNiels Sascha Reedijk \returns \c true if the string is valid, or \c false if it is not. 35a8003a70SNiels Sascha Reedijk */ 36a8003a70SNiels Sascha Reedijk static inline bool 37a8003a70SNiels Sascha Reedijk validate_value_string(const std::string_view& string) 38a8003a70SNiels Sascha Reedijk { 39a8003a70SNiels Sascha Reedijk for (auto it = string.cbegin(); it < string.cend(); it++) { 40a8003a70SNiels Sascha Reedijk if ((*it >= 0 && *it < 32) || *it == 127 || *it == '\t') 41a8003a70SNiels Sascha Reedijk return false; 42a8003a70SNiels Sascha Reedijk } 43a8003a70SNiels Sascha Reedijk return true; 44a8003a70SNiels Sascha Reedijk } 45a8003a70SNiels Sascha Reedijk 46a8003a70SNiels Sascha Reedijk 478ccf8fb4SNiels Sascha Reedijk /*! 48a8003a70SNiels Sascha Reedijk \brief Case insensitively compare two string_views. 49a8003a70SNiels Sascha Reedijk 50a8003a70SNiels Sascha Reedijk Inspired by https://stackoverflow.com/a/4119881 51a8003a70SNiels Sascha Reedijk */ 52a8003a70SNiels Sascha Reedijk static inline bool 53a8003a70SNiels Sascha Reedijk iequals(const std::string_view& a, const std::string_view& b) 54a8003a70SNiels Sascha Reedijk { 55a8003a70SNiels Sascha Reedijk return std::equal( 56a8003a70SNiels Sascha Reedijk a.begin(), a.end(), 57a8003a70SNiels Sascha Reedijk b.begin(), b.end(), 58a8003a70SNiels Sascha Reedijk [](char a, char b) { 59a8003a70SNiels Sascha Reedijk return tolower(a) == tolower(b); 60a8003a70SNiels Sascha Reedijk }); 61a8003a70SNiels Sascha Reedijk } 62a8003a70SNiels Sascha Reedijk 63a8003a70SNiels Sascha Reedijk 648ccf8fb4SNiels Sascha Reedijk /*! 658ccf8fb4SNiels Sascha Reedijk \brief Trim whitespace from the beginning and end of a string_view 668ccf8fb4SNiels Sascha Reedijk 678ccf8fb4SNiels Sascha Reedijk Inspired by: 688ccf8fb4SNiels Sascha Reedijk https://terrislinenbach.medium.com/trimming-whitespace-from-a-string-view-6795e18b108f 698ccf8fb4SNiels Sascha Reedijk */ 708ccf8fb4SNiels Sascha Reedijk static inline std::string_view 718ccf8fb4SNiels Sascha Reedijk trim(std::string_view in) 728ccf8fb4SNiels Sascha Reedijk { 738ccf8fb4SNiels Sascha Reedijk auto left = in.begin(); 748ccf8fb4SNiels Sascha Reedijk for (;; ++left) { 758ccf8fb4SNiels Sascha Reedijk if (left == in.end()) 768ccf8fb4SNiels Sascha Reedijk return std::string_view(); 778ccf8fb4SNiels Sascha Reedijk if (!isspace(*left)) 788ccf8fb4SNiels Sascha Reedijk break; 798ccf8fb4SNiels Sascha Reedijk } 808ccf8fb4SNiels Sascha Reedijk 818ccf8fb4SNiels Sascha Reedijk auto right = in.end() - 1; 828ccf8fb4SNiels Sascha Reedijk for (; right > left && isspace(*right); --right); 838ccf8fb4SNiels Sascha Reedijk 848ccf8fb4SNiels Sascha Reedijk return std::string_view(left, std::distance(left, right) + 1); 858ccf8fb4SNiels Sascha Reedijk } 868ccf8fb4SNiels Sascha Reedijk 878ccf8fb4SNiels Sascha Reedijk 88a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::InvalidHeader 89a8003a70SNiels Sascha Reedijk 90a8003a70SNiels Sascha Reedijk 91a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::InvalidInput(const char* origin, BString input) 92a8003a70SNiels Sascha Reedijk : 93a8003a70SNiels Sascha Reedijk BError(origin), 94a8003a70SNiels Sascha Reedijk input(std::move(input)) 95a8003a70SNiels Sascha Reedijk { 96a8003a70SNiels Sascha Reedijk 97a8003a70SNiels Sascha Reedijk } 98a8003a70SNiels Sascha Reedijk 99a8003a70SNiels Sascha Reedijk 100a8003a70SNiels Sascha Reedijk const char* 101a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::Message() const noexcept 102a8003a70SNiels Sascha Reedijk { 103a8003a70SNiels Sascha Reedijk return "Invalid format or unsupported characters in input"; 104a8003a70SNiels Sascha Reedijk } 105a8003a70SNiels Sascha Reedijk 106a8003a70SNiels Sascha Reedijk 107a8003a70SNiels Sascha Reedijk BString 108a8003a70SNiels Sascha Reedijk BHttpFields::InvalidInput::DebugMessage() const 109a8003a70SNiels Sascha Reedijk { 110a8003a70SNiels Sascha Reedijk BString output = BError::DebugMessage(); 111a8003a70SNiels Sascha Reedijk output << "\t " << input << "\n"; 112a8003a70SNiels Sascha Reedijk return output; 113a8003a70SNiels Sascha Reedijk } 114a8003a70SNiels Sascha Reedijk 115a8003a70SNiels Sascha Reedijk 116a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::Name 117a8003a70SNiels Sascha Reedijk 118a8003a70SNiels Sascha Reedijk 1198ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName() noexcept 1208ccf8fb4SNiels Sascha Reedijk : fName(std::string_view()) 1218ccf8fb4SNiels Sascha Reedijk { 1228ccf8fb4SNiels Sascha Reedijk 1238ccf8fb4SNiels Sascha Reedijk } 1248ccf8fb4SNiels Sascha Reedijk 1258ccf8fb4SNiels Sascha Reedijk 1268ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(const std::string_view& name) noexcept 127a8003a70SNiels Sascha Reedijk : fName(name) 128a8003a70SNiels Sascha Reedijk { 129a8003a70SNiels Sascha Reedijk 130a8003a70SNiels Sascha Reedijk } 131a8003a70SNiels Sascha Reedijk 132a8003a70SNiels Sascha Reedijk 133a8003a70SNiels Sascha Reedijk /*! 1348ccf8fb4SNiels Sascha Reedijk \brief Copy constructor; 135a8003a70SNiels Sascha Reedijk */ 1368ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(const FieldName& other) noexcept = default; 137a8003a70SNiels Sascha Reedijk 138a8003a70SNiels Sascha Reedijk 139a8003a70SNiels Sascha Reedijk /*! 140a8003a70SNiels Sascha Reedijk \brief Move constructor 141a8003a70SNiels Sascha Reedijk 142a8003a70SNiels Sascha Reedijk Moving leaves the other object in the empty state. It is implemented to satisfy the internal 143a8003a70SNiels Sascha Reedijk requirements of BHttpFields and std::list<Field>. Once an object is moved from it must no 144a8003a70SNiels Sascha Reedijk longer be used as an entry in a BHttpFields object. 145a8003a70SNiels Sascha Reedijk */ 146a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::FieldName(FieldName&& other) noexcept 147a8003a70SNiels Sascha Reedijk : fName(std::move(other.fName)) 148a8003a70SNiels Sascha Reedijk { 149a8003a70SNiels Sascha Reedijk other.fName = std::string_view(); 150a8003a70SNiels Sascha Reedijk } 151a8003a70SNiels Sascha Reedijk 152a8003a70SNiels Sascha Reedijk 153a8003a70SNiels Sascha Reedijk /*! 1548ccf8fb4SNiels Sascha Reedijk \brief Copy assignment; 155a8003a70SNiels Sascha Reedijk */ 156a8003a70SNiels Sascha Reedijk BHttpFields::FieldName& 1578ccf8fb4SNiels Sascha Reedijk BHttpFields::FieldName::operator=(const BHttpFields::FieldName& other) noexcept = default; 158a8003a70SNiels Sascha Reedijk 159a8003a70SNiels Sascha Reedijk 160a8003a70SNiels Sascha Reedijk /*! 161a8003a70SNiels Sascha Reedijk \brief Move assignment 162a8003a70SNiels Sascha Reedijk 163a8003a70SNiels Sascha Reedijk Moving leaves the other object in the empty state. It is implemented to satisfy the internal 164a8003a70SNiels Sascha Reedijk requirements of BHttpFields and std::list<Field>. Once an object is moved from it must no 165a8003a70SNiels Sascha Reedijk longer be used as an entry in a BHttpFields object. 166a8003a70SNiels Sascha Reedijk */ 167a8003a70SNiels Sascha Reedijk BHttpFields::FieldName& 168a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator=(BHttpFields::FieldName&& other) noexcept 169a8003a70SNiels Sascha Reedijk { 170a8003a70SNiels Sascha Reedijk fName = std::move(other.fName); 171a8003a70SNiels Sascha Reedijk other.fName = std::string_view(); 172a8003a70SNiels Sascha Reedijk return *this; 173a8003a70SNiels Sascha Reedijk } 174a8003a70SNiels Sascha Reedijk 175a8003a70SNiels Sascha Reedijk 176a8003a70SNiels Sascha Reedijk bool 177a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const BString& other) const noexcept 178a8003a70SNiels Sascha Reedijk { 1798ccf8fb4SNiels Sascha Reedijk return iequals(fName, std::string_view(other.String())); 180a8003a70SNiels Sascha Reedijk } 181a8003a70SNiels Sascha Reedijk 182a8003a70SNiels Sascha Reedijk 183a8003a70SNiels Sascha Reedijk bool 184a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const std::string_view& other) const noexcept 185a8003a70SNiels Sascha Reedijk { 1868ccf8fb4SNiels Sascha Reedijk return iequals(fName, other); 187a8003a70SNiels Sascha Reedijk } 188a8003a70SNiels Sascha Reedijk 189a8003a70SNiels Sascha Reedijk 190a8003a70SNiels Sascha Reedijk bool 191a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator==(const BHttpFields::FieldName& other) const noexcept 192a8003a70SNiels Sascha Reedijk { 1938ccf8fb4SNiels Sascha Reedijk return iequals(fName, other.fName); 194a8003a70SNiels Sascha Reedijk } 195a8003a70SNiels Sascha Reedijk 196a8003a70SNiels Sascha Reedijk 197a8003a70SNiels Sascha Reedijk BHttpFields::FieldName::operator std::string_view() const 198a8003a70SNiels Sascha Reedijk { 1998ccf8fb4SNiels Sascha Reedijk return fName; 200a8003a70SNiels Sascha Reedijk } 201a8003a70SNiels Sascha Reedijk 202a8003a70SNiels Sascha Reedijk 203a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields::Field 204a8003a70SNiels Sascha Reedijk 205a8003a70SNiels Sascha Reedijk 206a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field() noexcept 207a8003a70SNiels Sascha Reedijk : fName(std::string_view()), fValue(std::string_view()) 208a8003a70SNiels Sascha Reedijk { 209a8003a70SNiels Sascha Reedijk 210a8003a70SNiels Sascha Reedijk } 211a8003a70SNiels Sascha Reedijk 212a8003a70SNiels Sascha Reedijk 213a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(const std::string_view& name, const std::string_view& value) 214a8003a70SNiels Sascha Reedijk { 215cb67e348SNiels Sascha Reedijk if (name.length() == 0 || !validate_http_token_string(name)) 2168ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(name.data(), name.size())); 217a8003a70SNiels Sascha Reedijk if (value.length() == 0 || !validate_value_string(value)) 218a8003a70SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(value.data(), value.length())); 219a8003a70SNiels Sascha Reedijk 2208ccf8fb4SNiels Sascha Reedijk BString rawField(name.data(), name.size()); 2218ccf8fb4SNiels Sascha Reedijk rawField << ": "; 2228ccf8fb4SNiels Sascha Reedijk rawField.Append(value.data(), value.size()); 2238ccf8fb4SNiels Sascha Reedijk 2248ccf8fb4SNiels Sascha Reedijk fName = std::string_view(rawField.String(), name.size()); 2258ccf8fb4SNiels Sascha Reedijk fValue = std::string_view(rawField.String() + name.size() + 2, value.size()); 2268ccf8fb4SNiels Sascha Reedijk fRawField = std::move(rawField); 227a8003a70SNiels Sascha Reedijk } 2288ccf8fb4SNiels Sascha Reedijk 2298ccf8fb4SNiels Sascha Reedijk 2308ccf8fb4SNiels Sascha Reedijk BHttpFields::Field::Field(BString& field) 2318ccf8fb4SNiels Sascha Reedijk { 2328ccf8fb4SNiels Sascha Reedijk // Check if the input contains a key, a separator and a value. 2338ccf8fb4SNiels Sascha Reedijk auto separatorIndex = field.FindFirst(':'); 2348ccf8fb4SNiels Sascha Reedijk if (separatorIndex <= 0) 2358ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, field); 2368ccf8fb4SNiels Sascha Reedijk 2378ccf8fb4SNiels Sascha Reedijk // Get the name and the value. Remove whitespace around the value. 2388ccf8fb4SNiels Sascha Reedijk auto name = std::string_view(field.String(), separatorIndex); 2398ccf8fb4SNiels Sascha Reedijk auto value = trim(std::string_view(field.String() + separatorIndex + 1)); 2408ccf8fb4SNiels Sascha Reedijk 2418ccf8fb4SNiels Sascha Reedijk if (name.length() == 0 || !validate_http_token_string(name)) 2428ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(name.data(), name.size())); 2438ccf8fb4SNiels Sascha Reedijk if (value.length() == 0 || !validate_value_string(value)) 2448ccf8fb4SNiels Sascha Reedijk throw BHttpFields::InvalidInput(__PRETTY_FUNCTION__, BString(value.data(), value.length())); 2458ccf8fb4SNiels Sascha Reedijk 2468ccf8fb4SNiels Sascha Reedijk fRawField = std::move(field); 2478ccf8fb4SNiels Sascha Reedijk fName = name; 2488ccf8fb4SNiels Sascha Reedijk fValue = value; 249a8003a70SNiels Sascha Reedijk } 250a8003a70SNiels Sascha Reedijk 251a8003a70SNiels Sascha Reedijk 252a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(const BHttpFields::Field& other) 253a8003a70SNiels Sascha Reedijk : fName(std::string_view()), fValue(std::string_view()) 254a8003a70SNiels Sascha Reedijk { 2558ccf8fb4SNiels Sascha Reedijk if (other.IsEmpty()) { 2568ccf8fb4SNiels Sascha Reedijk fRawField = BString(); 2578ccf8fb4SNiels Sascha Reedijk fName = std::string_view(); 2588ccf8fb4SNiels Sascha Reedijk fValue = std::string_view(); 2598ccf8fb4SNiels Sascha Reedijk } else { 2608ccf8fb4SNiels Sascha Reedijk fRawField = other.fRawField; 2618ccf8fb4SNiels Sascha Reedijk auto nameSize = other.Name().fName.size(); 2628ccf8fb4SNiels Sascha Reedijk auto valueOffset = other.fValue.data() - other.fRawField.value().String(); 2638ccf8fb4SNiels Sascha Reedijk fName = std::string_view((*fRawField).String(), nameSize); 2648ccf8fb4SNiels Sascha Reedijk fValue = std::string_view((*fRawField).String() + valueOffset, other.fValue.size()); 265a8003a70SNiels Sascha Reedijk } 266a8003a70SNiels Sascha Reedijk } 267a8003a70SNiels Sascha Reedijk 268a8003a70SNiels Sascha Reedijk 269a8003a70SNiels Sascha Reedijk BHttpFields::Field::Field(BHttpFields::Field&& other) noexcept 2708ccf8fb4SNiels Sascha Reedijk : fRawField(std::move(other.fRawField)), fName(std::move(other.fName)), fValue(std::move(other.fValue)) 271a8003a70SNiels Sascha Reedijk { 272a8003a70SNiels Sascha Reedijk other.fName.fName = std::string_view(); 273a8003a70SNiels Sascha Reedijk other.fValue = std::string_view(); 274a8003a70SNiels Sascha Reedijk } 275a8003a70SNiels Sascha Reedijk 276a8003a70SNiels Sascha Reedijk 277a8003a70SNiels Sascha Reedijk BHttpFields::Field& 278a8003a70SNiels Sascha Reedijk BHttpFields::Field::operator=(const BHttpFields::Field& other) 279a8003a70SNiels Sascha Reedijk { 280a8003a70SNiels Sascha Reedijk if (other.IsEmpty()) { 2818ccf8fb4SNiels Sascha Reedijk fRawField = BString(); 282a8003a70SNiels Sascha Reedijk fName = std::string_view(); 283a8003a70SNiels Sascha Reedijk fValue = std::string_view(); 284a8003a70SNiels Sascha Reedijk } else { 2858ccf8fb4SNiels Sascha Reedijk fRawField = other.fRawField; 2868ccf8fb4SNiels Sascha Reedijk auto nameSize = other.Name().fName.size(); 2878ccf8fb4SNiels Sascha Reedijk auto valueOffset = other.fValue.data() - other.fRawField.value().String(); 2888ccf8fb4SNiels Sascha Reedijk fName = std::string_view((*fRawField).String(), nameSize); 2898ccf8fb4SNiels Sascha Reedijk fValue = std::string_view((*fRawField).String() + valueOffset, other.fValue.size()); 290a8003a70SNiels Sascha Reedijk } 291a8003a70SNiels Sascha Reedijk return *this; 292a8003a70SNiels Sascha Reedijk } 293a8003a70SNiels Sascha Reedijk 294a8003a70SNiels Sascha Reedijk 295a8003a70SNiels Sascha Reedijk BHttpFields::Field& 296a8003a70SNiels Sascha Reedijk BHttpFields::Field::operator=(BHttpFields::Field&& other) noexcept 297a8003a70SNiels Sascha Reedijk { 2988ccf8fb4SNiels Sascha Reedijk fRawField = std::move(other.fRawField); 299a8003a70SNiels Sascha Reedijk fName = std::move(other.fName); 300a8003a70SNiels Sascha Reedijk other.fName.fName = std::string_view(); 301a8003a70SNiels Sascha Reedijk fValue = std::move(other.fValue); 302a8003a70SNiels Sascha Reedijk fValue = std::string_view(); 303a8003a70SNiels Sascha Reedijk return *this; 304a8003a70SNiels Sascha Reedijk } 305a8003a70SNiels Sascha Reedijk 306a8003a70SNiels Sascha Reedijk 307a8003a70SNiels Sascha Reedijk const BHttpFields::FieldName& 308a8003a70SNiels Sascha Reedijk BHttpFields::Field::Name() const noexcept 309a8003a70SNiels Sascha Reedijk { 310a8003a70SNiels Sascha Reedijk return fName; 311a8003a70SNiels Sascha Reedijk } 312a8003a70SNiels Sascha Reedijk 313a8003a70SNiels Sascha Reedijk 314a8003a70SNiels Sascha Reedijk std::string_view 315a8003a70SNiels Sascha Reedijk BHttpFields::Field::Value() const noexcept 316a8003a70SNiels Sascha Reedijk { 3178ccf8fb4SNiels Sascha Reedijk return fValue; 318a8003a70SNiels Sascha Reedijk } 3198ccf8fb4SNiels Sascha Reedijk 3208ccf8fb4SNiels Sascha Reedijk 3218ccf8fb4SNiels Sascha Reedijk std::string_view 3228ccf8fb4SNiels Sascha Reedijk BHttpFields::Field::RawField() const noexcept 3238ccf8fb4SNiels Sascha Reedijk { 3248ccf8fb4SNiels Sascha Reedijk if (fRawField) 3258ccf8fb4SNiels Sascha Reedijk return std::string_view((*fRawField).String(), (*fRawField).Length()); 3268ccf8fb4SNiels Sascha Reedijk else 3278ccf8fb4SNiels Sascha Reedijk return std::string_view(); 328a8003a70SNiels Sascha Reedijk } 329a8003a70SNiels Sascha Reedijk 330a8003a70SNiels Sascha Reedijk 331a8003a70SNiels Sascha Reedijk bool 332a8003a70SNiels Sascha Reedijk BHttpFields::Field::IsEmpty() const noexcept 333a8003a70SNiels Sascha Reedijk { 334a8003a70SNiels Sascha Reedijk // The object is either fully empty, or it has data, so we only have to check fValue. 3358ccf8fb4SNiels Sascha Reedijk return !fRawField.has_value(); 336a8003a70SNiels Sascha Reedijk } 337a8003a70SNiels Sascha Reedijk 338a8003a70SNiels Sascha Reedijk 339a8003a70SNiels Sascha Reedijk // #pragma mark -- BHttpFields 340a8003a70SNiels Sascha Reedijk 341a8003a70SNiels Sascha Reedijk 342a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields() 343a8003a70SNiels Sascha Reedijk { 344a8003a70SNiels Sascha Reedijk 345a8003a70SNiels Sascha Reedijk } 346a8003a70SNiels Sascha Reedijk 347a8003a70SNiels Sascha Reedijk 348a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(std::initializer_list<BHttpFields::Field> fields) 349a8003a70SNiels Sascha Reedijk { 3508ccf8fb4SNiels Sascha Reedijk AddFields(fields); 351a8003a70SNiels Sascha Reedijk } 352a8003a70SNiels Sascha Reedijk 353a8003a70SNiels Sascha Reedijk 354a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(const BHttpFields& other) = default; 355a8003a70SNiels Sascha Reedijk 356a8003a70SNiels Sascha Reedijk 357a8003a70SNiels Sascha Reedijk BHttpFields::BHttpFields(BHttpFields&& other) 358a8003a70SNiels Sascha Reedijk : fFields(std::move(other.fFields)) 359a8003a70SNiels Sascha Reedijk { 360a8003a70SNiels Sascha Reedijk // Explicitly clear the other list, as the C++ standard does not specify that the other list 361a8003a70SNiels Sascha Reedijk // will be empty. 362a8003a70SNiels Sascha Reedijk other.fFields.clear(); 363a8003a70SNiels Sascha Reedijk } 364a8003a70SNiels Sascha Reedijk 365a8003a70SNiels Sascha Reedijk 366a8003a70SNiels Sascha Reedijk BHttpFields::~BHttpFields() noexcept 367a8003a70SNiels Sascha Reedijk { 368a8003a70SNiels Sascha Reedijk 369a8003a70SNiels Sascha Reedijk } 370a8003a70SNiels Sascha Reedijk 371a8003a70SNiels Sascha Reedijk 372a8003a70SNiels Sascha Reedijk BHttpFields& 373a8003a70SNiels Sascha Reedijk BHttpFields::operator=(const BHttpFields& other) = default; 374a8003a70SNiels Sascha Reedijk 375a8003a70SNiels Sascha Reedijk 376a8003a70SNiels Sascha Reedijk BHttpFields& 377a8003a70SNiels Sascha Reedijk BHttpFields::operator=(BHttpFields&& other) noexcept 378a8003a70SNiels Sascha Reedijk { 379a8003a70SNiels Sascha Reedijk fFields = std::move(other.fFields); 380a8003a70SNiels Sascha Reedijk 381a8003a70SNiels Sascha Reedijk // Explicitly clear the other list, as the C++ standard does not specify that the other list 382a8003a70SNiels Sascha Reedijk // will be empty. 383a8003a70SNiels Sascha Reedijk other.fFields.clear(); 384a8003a70SNiels Sascha Reedijk return *this; 385a8003a70SNiels Sascha Reedijk } 386a8003a70SNiels Sascha Reedijk 387a8003a70SNiels Sascha Reedijk 388a8003a70SNiels Sascha Reedijk const BHttpFields::Field& 389a8003a70SNiels Sascha Reedijk BHttpFields::operator[](size_t index) const 390a8003a70SNiels Sascha Reedijk { 391a8003a70SNiels Sascha Reedijk if (index >= fFields.size()) 392a8003a70SNiels Sascha Reedijk throw BRuntimeError(__PRETTY_FUNCTION__, "Index out of bounds"); 393a8003a70SNiels Sascha Reedijk auto it = fFields.cbegin(); 394a8003a70SNiels Sascha Reedijk std::advance(it, index); 395a8003a70SNiels Sascha Reedijk return *it; 396a8003a70SNiels Sascha Reedijk } 397a8003a70SNiels Sascha Reedijk 398a8003a70SNiels Sascha Reedijk 399a8003a70SNiels Sascha Reedijk void 400a8003a70SNiels Sascha Reedijk BHttpFields::AddField(const std::string_view& name, const std::string_view& value) 401a8003a70SNiels Sascha Reedijk { 4028ccf8fb4SNiels Sascha Reedijk fFields.emplace_back(name, value); 4038ccf8fb4SNiels Sascha Reedijk } 4048ccf8fb4SNiels Sascha Reedijk 4058ccf8fb4SNiels Sascha Reedijk 4068ccf8fb4SNiels Sascha Reedijk void 4078ccf8fb4SNiels Sascha Reedijk BHttpFields::AddField(BString& field) 4088ccf8fb4SNiels Sascha Reedijk { 4098ccf8fb4SNiels Sascha Reedijk fFields.emplace_back(field); 410a8003a70SNiels Sascha Reedijk } 411a8003a70SNiels Sascha Reedijk 412a8003a70SNiels Sascha Reedijk 413a8003a70SNiels Sascha Reedijk void 414d9a4c607SNiels Sascha Reedijk BHttpFields::AddFields(std::initializer_list<Field> fields) 415d9a4c607SNiels Sascha Reedijk { 416d9a4c607SNiels Sascha Reedijk for (auto& field: fields) { 417d9a4c607SNiels Sascha Reedijk if (!field.IsEmpty()) 4188ccf8fb4SNiels Sascha Reedijk fFields.push_back(std::move(field)); 419d9a4c607SNiels Sascha Reedijk } 420d9a4c607SNiels Sascha Reedijk } 421d9a4c607SNiels Sascha Reedijk 422d9a4c607SNiels Sascha Reedijk 423d9a4c607SNiels Sascha Reedijk void 424a8003a70SNiels Sascha Reedijk BHttpFields::RemoveField(const std::string_view& name) noexcept 425a8003a70SNiels Sascha Reedijk { 426a8003a70SNiels Sascha Reedijk for(auto it = FindField(name); it != end(); it = FindField(name)) { 427a8003a70SNiels Sascha Reedijk fFields.erase(it); 428a8003a70SNiels Sascha Reedijk } 429a8003a70SNiels Sascha Reedijk } 430a8003a70SNiels Sascha Reedijk 431a8003a70SNiels Sascha Reedijk 432a8003a70SNiels Sascha Reedijk void 433a8003a70SNiels Sascha Reedijk BHttpFields::RemoveField(ConstIterator it) noexcept 434a8003a70SNiels Sascha Reedijk { 435a8003a70SNiels Sascha Reedijk fFields.erase(it); 436a8003a70SNiels Sascha Reedijk } 437a8003a70SNiels Sascha Reedijk 438a8003a70SNiels Sascha Reedijk 439a8003a70SNiels Sascha Reedijk void 440a8003a70SNiels Sascha Reedijk BHttpFields::MakeEmpty() noexcept 441a8003a70SNiels Sascha Reedijk { 442a8003a70SNiels Sascha Reedijk fFields.clear(); 443a8003a70SNiels Sascha Reedijk } 444a8003a70SNiels Sascha Reedijk 445a8003a70SNiels Sascha Reedijk 446a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator 447a8003a70SNiels Sascha Reedijk BHttpFields::FindField(const std::string_view& name) const noexcept 448a8003a70SNiels Sascha Reedijk { 449a8003a70SNiels Sascha Reedijk for (auto it = fFields.cbegin(); it != fFields.cend(); it++) { 450a8003a70SNiels Sascha Reedijk if ((*it).Name() == name) 451a8003a70SNiels Sascha Reedijk return it; 452a8003a70SNiels Sascha Reedijk } 453a8003a70SNiels Sascha Reedijk return fFields.cend(); 454a8003a70SNiels Sascha Reedijk } 455a8003a70SNiels Sascha Reedijk 456a8003a70SNiels Sascha Reedijk 457a8003a70SNiels Sascha Reedijk size_t 458a8003a70SNiels Sascha Reedijk BHttpFields::CountFields() const noexcept 459a8003a70SNiels Sascha Reedijk { 460a8003a70SNiels Sascha Reedijk return fFields.size(); 461a8003a70SNiels Sascha Reedijk } 462a8003a70SNiels Sascha Reedijk 463a8003a70SNiels Sascha Reedijk 464*7b1d966cSNiels Sascha Reedijk size_t 465*7b1d966cSNiels Sascha Reedijk BHttpFields::CountFields(const std::string_view& name) const noexcept 466*7b1d966cSNiels Sascha Reedijk { 467*7b1d966cSNiels Sascha Reedijk size_t count = 0; 468*7b1d966cSNiels Sascha Reedijk for (auto it = fFields.cbegin(); it != fFields.cend(); it++) { 469*7b1d966cSNiels Sascha Reedijk if ((*it).Name() == name) 470*7b1d966cSNiels Sascha Reedijk count += 1; 471*7b1d966cSNiels Sascha Reedijk } 472*7b1d966cSNiels Sascha Reedijk return count; 473*7b1d966cSNiels Sascha Reedijk } 474*7b1d966cSNiels Sascha Reedijk 475*7b1d966cSNiels Sascha Reedijk 476a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator 477a8003a70SNiels Sascha Reedijk BHttpFields::begin() const noexcept 478a8003a70SNiels Sascha Reedijk { 479a8003a70SNiels Sascha Reedijk return fFields.cbegin(); 480a8003a70SNiels Sascha Reedijk } 481a8003a70SNiels Sascha Reedijk 482a8003a70SNiels Sascha Reedijk 483a8003a70SNiels Sascha Reedijk BHttpFields::ConstIterator 484a8003a70SNiels Sascha Reedijk BHttpFields::end() const noexcept 485a8003a70SNiels Sascha Reedijk { 486a8003a70SNiels Sascha Reedijk return fFields.cend(); 487a8003a70SNiels Sascha Reedijk } 488