Line data Source code
1 : #include "source/extensions/http/stateful_session/cookie/cookie.h" 2 : 3 : #include "source/common/http/headers.h" 4 : #include "source/common/runtime/runtime_features.h" 5 : 6 : namespace Envoy { 7 : namespace Extensions { 8 : namespace Http { 9 : namespace StatefulSession { 10 : namespace Cookie { 11 : 12 : void CookieBasedSessionStateFactory::SessionStateImpl::onUpdate( 13 0 : const Upstream::HostDescription& host, Envoy::Http::ResponseHeaderMap& headers) { 14 0 : absl::string_view host_address = host.address()->asStringView(); 15 0 : std::string encoded_address; 16 0 : if (!upstream_address_.has_value() || host_address != upstream_address_.value()) { 17 0 : if (Runtime::runtimeFeatureEnabled( 18 0 : "envoy.reloadable_features.stateful_session_encode_ttl_in_cookie")) { 19 0 : auto expiry_time = std::chrono::duration_cast<std::chrono::seconds>( 20 0 : (time_source_.monotonicTime() + std::chrono::seconds(factory_.ttl_)).time_since_epoch()); 21 : // Build proto message 22 0 : envoy::Cookie cookie; 23 0 : cookie.set_address(std::string(host_address)); 24 0 : cookie.set_expires(expiry_time.count()); 25 0 : std::string proto_string; 26 0 : cookie.SerializeToString(&proto_string); 27 : 28 0 : encoded_address = Envoy::Base64::encode(proto_string.data(), proto_string.length()); 29 0 : } else { 30 0 : encoded_address = Envoy::Base64::encode(host_address.data(), host_address.length()); 31 0 : } 32 0 : headers.addReferenceKey(Envoy::Http::Headers::get().SetCookie, 33 0 : factory_.makeSetCookie(encoded_address)); 34 0 : } 35 0 : } 36 : 37 : CookieBasedSessionStateFactory::CookieBasedSessionStateFactory( 38 : const CookieBasedSessionStateProto& config, TimeSource& time_source) 39 : : name_(config.cookie().name()), ttl_(config.cookie().ttl().seconds()), 40 0 : path_(config.cookie().path()), time_source_(time_source) { 41 0 : if (name_.empty()) { 42 0 : throw EnvoyException("Cookie key cannot be empty for cookie based stateful sessions"); 43 0 : } 44 : 45 : // If no cookie path is specified or root cookie path is specified then this session state will 46 : // be enabled for any request. 47 0 : if (path_.empty() || path_ == "/") { 48 0 : path_matcher_ = [](absl::string_view) { return true; }; 49 0 : return; 50 0 : } 51 : 52 : // If specified cookie path is ends with '/' then this session state will be enabled for the 53 : // requests with a path that starts with the cookie path. 54 : // For example the cookie path '/foo/' will matches request paths '/foo/bar' or '/foo/dir', but 55 : // will not match request path '/foo'. 56 0 : if (absl::EndsWith(path_, "/")) { 57 0 : path_matcher_ = [path = path_](absl::string_view request_path) { 58 0 : return absl::StartsWith(request_path, path); 59 0 : }; 60 0 : return; 61 0 : } 62 : 63 0 : path_matcher_ = [path = path_](absl::string_view request_path) { 64 0 : if (absl::StartsWith(request_path, path)) { 65 : // Request path is same with cookie path. 66 0 : if (request_path.size() == path.size()) { 67 0 : return true; 68 0 : } 69 : 70 : // The next character of the matching part should be the slash ('/'), question mark ('?') or 71 : // number sign ('#'). 72 0 : ASSERT(request_path.size() > path.size()); 73 0 : const char next_char = request_path[path.size()]; 74 0 : if (next_char == '/' || next_char == '?' || next_char == '#') { 75 0 : return true; 76 0 : } 77 0 : } 78 0 : return false; 79 0 : }; 80 0 : } 81 : 82 : } // namespace Cookie 83 : } // namespace StatefulSession 84 : } // namespace Http 85 : } // namespace Extensions 86 : } // namespace Envoy