1 /** @file 2 3 A brief file description 4 5 @section license License 6 7 Licensed to the Apache Software Foundation (ASF) under one 8 or more contributor license agreements. See the NOTICE file 9 distributed with this work for additional information 10 regarding copyright ownership. The ASF licenses this file 11 to you under the Apache License, Version 2.0 (the 12 "License"); you may not use this file except in compliance 13 with the License. You may obtain a copy of the License at 14 15 http://www.apache.org/licenses/LICENSE-2.0 16 17 Unless required by applicable law or agreed to in writing, software 18 distributed under the License is distributed on an "AS IS" BASIS, 19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 See the License for the specific language governing permissions and 21 limitations under the License. 22 */ 23 24 #pragma once 25 26 #include <list> 27 28 #include <cstring> 29 #include "ComponentBase.h" 30 #include "StringHash.h" 31 #include "HttpHeader.h" 32 #include "Utils.h" 33 34 namespace EsiLib 35 { 36 class Variables : private ComponentBase 37 { 38 public: Variables(const char * debug_tag,ComponentBase::Debug debug_func,ComponentBase::Error error_func,Utils::HeaderValueList allowlistCookies)39 Variables(const char *debug_tag, ComponentBase::Debug debug_func, ComponentBase::Error error_func, 40 Utils::HeaderValueList allowlistCookies) 41 : ComponentBase(debug_tag, debug_func, error_func), 42 _headers_parsed(false), 43 _query_string(""), 44 _query_string_parsed(false), 45 _cookie_jar_created(false) 46 { 47 _allowlistCookies.insert(_allowlistCookies.end(), allowlistCookies.begin(), allowlistCookies.end()); 48 }; 49 50 /** currently 'host', 'referer', 'accept-language', 'cookie' and 'user-agent' headers are parsed */ 51 void populate(const HttpHeader &header); 52 53 void populate(const HttpHeaderList & headers)54 populate(const HttpHeaderList &headers) 55 { 56 for (const auto &header : headers) { 57 populate(header); 58 } 59 }; 60 61 void 62 populate(const char *query_string, int query_string_len = -1) 63 { 64 if (query_string && (query_string_len != 0)) { 65 if (query_string_len == -1) { 66 query_string_len = strlen(query_string); 67 } 68 if (_query_string_parsed) { 69 _parseQueryString(query_string, query_string_len); 70 } else { 71 _query_string.assign(query_string, query_string_len); 72 } 73 } 74 } 75 76 /** returns value of specified variable; empty string returned for unknown variable; key 77 * has to be prefixed with 'http_' string for all variable names except 'query_string' */ 78 const std::string &getValue(const std::string &name) const; 79 80 /** convenient alternative for method above */ 81 const std::string & 82 getValue(const char *name, int name_len = -1) const 83 { 84 if (!name) { 85 return EMPTY_STRING; 86 } 87 std::string var_name; 88 if (name_len == -1) { 89 var_name.assign(name); 90 } else { 91 var_name.assign(name, name_len); 92 } 93 return getValue(var_name); 94 } 95 96 void clear(); 97 ~Variables()98 ~Variables() override { _releaseCookieJar(); }; 99 100 // noncopyable 101 Variables(const Variables &) = delete; // non-copyable 102 Variables &operator=(const Variables &) = delete; // non-copyable 103 104 private: 105 static const std::string EMPTY_STRING; 106 static const std::string TRUE_STRING; 107 static const std::string VENDOR_STRING; 108 static const std::string VERSION_STRING; 109 static const std::string PLATFORM_STRING; 110 111 enum SimpleHeader { 112 HTTP_HOST = 0, 113 HTTP_REFERER = 1, 114 }; 115 static const std::string SIMPLE_HEADERS[]; // indices should map to enum values above 116 117 enum SpecialHeader { 118 HTTP_ACCEPT_LANGUAGE = 0, 119 HTTP_COOKIE = 1, 120 HTTP_USER_AGENT = 2, 121 QUERY_STRING = 3, 122 HTTP_HEADER = 4, 123 }; 124 static const std::string SPECIAL_HEADERS[]; // indices should map to enum values above 125 126 // normalized versions of the headers above; indices should correspond correctly 127 static const std::string NORM_SIMPLE_HEADERS[]; 128 static const std::string NORM_SPECIAL_HEADERS[]; // indices should again map to enum values 129 130 static const int N_SIMPLE_HEADERS = HTTP_REFERER + 1; 131 static const int N_SPECIAL_HEADERS = HTTP_HEADER + 1; 132 133 StringHash _simple_data; 134 StringHash _dict_data[N_SPECIAL_HEADERS]; 135 136 inline std::string &_toUpperCase(std::string &str) const; 137 inline int _searchHeaders(const std::string headers[], const char *name, int name_len) const; 138 bool _parseDictVariable(const std::string &variable, const char *&header, int &header_len, const char *&attr, 139 int &attr_len) const; 140 void _parseCookieString(const char *str, int str_len); 141 void _parseUserAgentString(const char *str, int str_len); 142 void _parseAcceptLangString(const char *str, int str_len); 143 inline void _parseSimpleHeader(SimpleHeader hdr, const std::string &value); 144 inline void _parseSimpleHeader(SimpleHeader hdr, const char *value, int value_len); 145 void _parseSpecialHeader(SpecialHeader hdr, const char *value, int value_len); 146 void _parseCachedHeaders(); 147 148 inline void _insert(StringHash &hash, const std::string &key, const std::string &value); 149 150 Utils::HeaderValueList _cached_simple_headers[N_SIMPLE_HEADERS]; 151 Utils::HeaderValueList _cached_special_headers[N_SPECIAL_HEADERS]; 152 153 Utils::HeaderValueList _allowlistCookies; 154 std::string _cookie_str; 155 bool _headers_parsed; 156 std::string _query_string; 157 bool _query_string_parsed; 158 159 void _parseHeader(const char *name, int name_len, const char *value, int value_len); 160 void _parseQueryString(const char *query_string, int query_string_len); 161 162 StringKeyHash<StringHash> _sub_cookies; 163 bool _cookie_jar_created; 164 165 void _parseSubCookies(); 166 167 inline void _releaseCookieJar()168 _releaseCookieJar() 169 { 170 if (_cookie_jar_created) { 171 _sub_cookies.clear(); 172 _cookie_jar_created = false; 173 } 174 } 175 176 mutable std::string _cached_sub_cookie_value; 177 const std::string &_getSubCookieValue(const std::string &cookie_str, size_t cookie_part_divider) const; 178 }; 179 }; // namespace EsiLib 180