bes  Updated for version 3.20.10
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 
45 using std::string;
46 using std::map;
47 using std::pair;
48 using std::vector;
49 using std::endl;
50 using 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 
57 namespace http {
58 
59 EffectiveUrl::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:206
utility class for the HTTP catalog module
Definition: AllowedHosts.cc:55