bes Updated for version 3.20.13
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
59EffectiveUrl::EffectiveUrl() : http::url(""), d_response_header_names(), d_response_header_values() {
60 BESDEBUG(HTTP_MODULE, prolog << "created: " << ingest_time() << endl);
61};
62
69 bool EffectiveUrl::is_expired() {
70
71 BESDEBUG(MODULE, prolog << "BEGIN" << endl);
72 bool expired = false;
73 bool found = false;
74 string cc_hdr_val;
75
76 auto now = std::chrono::system_clock::now();
77 auto now_secs = std::chrono::time_point_cast<std::chrono::seconds>(now);
78 BESDEBUG(MODULE, prolog << "now_secs: " << now_secs.time_since_epoch().count() << endl);
79
80 get_header(CACHE_CONTROL_HEADER_KEY, cc_hdr_val, found);
81 if (found) {
82 BESDEBUG(MODULE, prolog << CACHE_CONTROL_HEADER_KEY << " '" << cc_hdr_val << "'" << endl);
83
84 // Example: 'Cache-Control: private, max-age=600'
85 string max_age_key("max-age=");
86 size_t max_age_index = cc_hdr_val.find(max_age_key);
87 if (max_age_index != cc_hdr_val.npos) {
88 string max_age_str = cc_hdr_val.substr(max_age_index + max_age_key.size());
89 long long msi;
90 std::istringstream(max_age_str) >> msi;
91 std::chrono::seconds max_age(msi);
92 auto itime = std::chrono::system_clock::from_time_t(ingest_time());
93 auto expires_time = std::chrono::time_point_cast<std::chrono::seconds>(itime + max_age);
94 expired = now_secs > expires_time;
95
96 BESDEBUG(MODULE, prolog << "expires_time: " << expires_time.time_since_epoch().count() <<
97 " threshold: " << HTTP_URL_REFRESH_THRESHOLD << endl);
98
99 BESDEBUG(MODULE, prolog << "expired: " << (expired ? "true" : "false") << endl);
100 }
101 }
102 if (!expired) {
103 expired = url::is_expired();
104 }
105 BESDEBUG(MODULE, prolog << "END expired: " << (expired ? "true" : "false") << endl);
106 return expired;
107 }
108
109
110
111
119 void EffectiveUrl::get_header(const std::string &name, std::string &value, bool &found ) {
120 found = false;
121 string lc_name = BESUtil::lowercase(name);
122 auto rname_itr = d_response_header_names.rbegin();
123 auto rvalue_itr = d_response_header_values.rbegin();
124 while(!found && rname_itr != d_response_header_names.rend()){
125 string hdr_name = *rname_itr;
126 found = (lc_name == hdr_name);
127 if(found){
128 value = *rvalue_itr;
129 }
130 ++rname_itr;
131 ++rvalue_itr;
132 }
133 }
134
139 string EffectiveUrl::dump(){
140 stringstream ss;
141 string indent_inc = " ";
142 string indent = indent_inc;
143
144 ss << url::dump();
145 auto name_itr = d_response_header_names.begin();
146 auto value_itr = d_response_header_values.begin();
147 while(name_itr!=d_response_header_names.end()){
148 ss << indent << "Header: " << *name_itr << ": " << *value_itr << endl;
149 ++name_itr;
150 ++value_itr;
151 }
152 return ss.str();
153 }
154
155
160 void EffectiveUrl::ingest_response_headers(const vector<string> &resp_hdrs)
161 {
162 d_resp_hdr_lines.clear();
163 d_resp_hdr_lines = resp_hdrs;
164 d_response_header_names.clear();
165 d_response_header_values.clear();
166
167 auto index = resp_hdrs.begin();
168 while(index!=resp_hdrs.end()){
169 size_t colon = (*index).find(":");
170 if(colon!=(*index).npos){
171 string key((*index).substr(0,colon));
172 key = BESUtil::lowercase(key);
173 string value((*index).substr(colon));
174 d_response_header_names.push_back(key);
175 d_response_header_values.push_back(value);
176 BESDEBUG(MODULE, prolog << "Ingested header: " << key << ": " << value << "(size: " << d_response_header_values.size() << ")" << endl);
177 }
178 else {
179 ERROR_LOG(prolog << "Encounter malformed response header! Missing ':' delimiter. SKIPPING" << endl);
180 }
181 index++;
182 }
183 }
184
185
186
187
188} // namespace http
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:254
utility class for the HTTP catalog module
Definition: AllowedHosts.cc:55