bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
EffectiveUrl.cc
1// -*- mode: c++; c-basic-offset:4 -*-
2//
3// EffectiveUrl.cc
4// This file is part of the BES http package, part of the Hyrax data server.
5
6// Copyright (c) 2020 OPeNDAP, Inc.
7// Author: Nathan Potter <ndp@opendap.org>
8//
9// This library is free software; you can redistribute it and/or
10// modify it under the terms of the GNU Lesser General Public
11// License as published by the Free Software Foundation; either
12// version 2.1 of the License, or (at your option) any later version.
13//
14// This library is distributed in the hope that it will be useful,
15// but WITHOUT ANY WARRANTY; without even the implied warranty of
16// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17// Lesser General Public License for more details.
18//
19// You should have received a copy of the GNU Lesser General Public
20// License along with this library; if not, write to the Free Software
21// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22//
23// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24
25// Authors:
26// ndp Nathan Potter <ndp@opendap.org>
27
28#include "config.h"
29
30#include <string>
31#include <sstream>
32#include <map>
33#include <vector>
34
35#include <chrono>
36
37#include "BESDebug.h"
38#include "BESUtil.h"
39#include "BESLog.h"
40
41#include "HttpNames.h"
42#include "url_impl.h"
43#include "EffectiveUrl.h"
44
45using std::string;
46using std::map;
47using std::pair;
48using std::vector;
49using std::endl;
50using std::stringstream;
51
52#define CACHE_CONTROL_HEADER_KEY "cache-control"
53
54#define MODULE HTTP_MODULE
55#define prolog std::string("EffectiveUrl::").append(__func__).append("() - ")
56
57namespace http {
58
66 BESDEBUG(MODULE, prolog << "BEGIN" << endl);
67 bool expired = false;
68 bool found = false;
69 string cc_hdr_val;
70
71 auto now = std::chrono::system_clock::now();
72 auto now_secs = std::chrono::time_point_cast<std::chrono::seconds>(now);
73 BESDEBUG(MODULE, prolog << "now_secs: " << now_secs.time_since_epoch().count() << endl);
74
75 get_header(CACHE_CONTROL_HEADER_KEY, cc_hdr_val, found);
76 if (found) {
77 BESDEBUG(MODULE, prolog << CACHE_CONTROL_HEADER_KEY << " '" << cc_hdr_val << "'" << endl);
78
79 // Example: 'Cache-Control: private, max-age=600'
80 string max_age_key{"max-age="};
81 size_t max_age_index = cc_hdr_val.find(max_age_key);
82 if (max_age_index != cc_hdr_val.npos) {
83 string max_age_str = cc_hdr_val.substr(max_age_index + max_age_key.size());
84 long long msi;
85 std::istringstream(max_age_str) >> msi;
86 std::chrono::seconds max_age(msi);
87 auto itime = std::chrono::system_clock::from_time_t(ingest_time());
88 auto expires_time = std::chrono::time_point_cast<std::chrono::seconds>(itime + max_age);
89 expired = now_secs > expires_time;
90
91 BESDEBUG(MODULE, prolog << "expires_time: " << expires_time.time_since_epoch().count() <<
92 " threshold: " << HTTP_URL_REFRESH_THRESHOLD << endl);
93
94 BESDEBUG(MODULE, prolog << "expired: " << (expired ? "true" : "false") << endl);
95 }
96 }
97 if (!expired) {
98 expired = url::is_expired();
99 }
100 BESDEBUG(MODULE, prolog << "END expired: " << (expired ? "true" : "false") << endl);
101 return expired;
102}
103
111void EffectiveUrl::get_header(const std::string &name, std::string &value, bool &found ) {
112 found = false;
113 string lc_name = BESUtil::lowercase(name);
114 auto rname_itr = d_response_header_names.rbegin();
115 auto rvalue_itr = d_response_header_values.rbegin();
116 while(!found && rname_itr != d_response_header_names.rend()){
117 string hdr_name = *rname_itr;
118 found = (lc_name == hdr_name);
119 if(found){
120 value = *rvalue_itr;
121 }
122 ++rname_itr;
123 ++rvalue_itr;
124 }
125}
126
131void EffectiveUrl::ingest_response_headers(const vector <string> &resp_hdrs) {
132 d_response_header_names.clear();
133 d_response_header_values.clear();
134
135 for (const auto &header: resp_hdrs){
136 size_t colon = header.find(':');
137 if (colon != string::npos) {
138 string key(header.substr(0, colon));
139 key = BESUtil::lowercase(key);
140 string value(header.substr(colon));
141 d_response_header_names.push_back(key);
142 d_response_header_values.push_back(value);
143 BESDEBUG(MODULE, prolog << "Ingested header: " << key << ": " << value << "(size: "
144 << d_response_header_values.size() << ")" << endl);
145 }
146 else {
147 ERROR_LOG(prolog + "Encounter malformed response header! Missing ':' delimiter. SKIPPING");
148 }
149 }
150}
151
157 stringstream ss;
158 string indent_inc = " ";
159 string indent = indent_inc;
160
161 ss << url::dump();
162 auto name_itr = d_response_header_names.begin();
163 auto value_itr = d_response_header_values.begin();
164 while(name_itr!=d_response_header_names.end()){
165 ss << indent << "Header: " << *name_itr << ": " << *value_itr << endl;
166 ++name_itr;
167 ++value_itr;
168 }
169 return ss.str();
170}
171
172} // namespace http
static std::string lowercase(const std::string &s)
Definition BESUtil.cc:257
std::string dump() override
A string dump of the instance.
bool is_expired() override
Returns true if URL is reusable, false otherwise.
void get_header(const std::string &name, std::string &value, bool &found)
get the value of the named header
void ingest_response_headers(const std::vector< std::string > &resp_hdrs)
Replaces the existing header names and values with the new response headers.
virtual std::string dump()
Definition url_impl.cc:295
virtual bool is_expired()
Definition url_impl.cc:212
utility class for the HTTP catalog module
Definition TheBESKeys.h:51