bes  Updated for version 3.20.6
HttpdCatalogUtils.cc
1 // HttpCatalogUtils.cc
2 // -*- mode: c++; c-basic-offset:4 -*-
3 //
4 // This file is part of httpd_catalog_module, A C++ module that can be loaded in to
5 // the OPeNDAP Back-End Server (BES) and is able to handle remote requests.
6 //
7 // Copyright (c) 2018 OPeNDAP, Inc.
8 // Author: Nathan Potter <ndp@opendap.org>
9 //
10 // This library is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU Lesser General Public
12 // License as published by the Free Software Foundation; either
13 // version 2.1 of the License, or (at your option) any later version.
14 //
15 // This library is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 // Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
25 
26 #include "config.h"
27 
28 #ifdef HAVE_UNISTD_H
29 #include <unistd.h>
30 #endif
31 
32 #include <cstdlib>
33 #include <cstring>
34 #include <map>
35 #include <vector>
36 
37 #include <curl/curl.h>
38 
39 #include <GNURegex.h>
40 #include <util.h>
41 
42 #include <BESUtil.h>
43 #include <BESCatalogUtils.h>
44 #include <BESCatalogList.h>
45 #include <BESCatalog.h>
46 #include <BESRegex.h>
47 #include <TheBESKeys.h>
48 #include <BESInternalError.h>
49 #include <BESDapError.h>
50 #include <BESNotFoundError.h>
51 #include <BESSyntaxUserError.h>
52 #include <BESDebug.h>
53 
54 #include "HttpdCatalogNames.h"
55 #include "HttpdCatalogUtils.h"
56 
57 using namespace libdap;
58 using namespace std;
59 
60 namespace httpd_catalog {
61 
62 // These are static class members
63 map<string, string> HttpdCatalogUtils::MimeList;
64 string HttpdCatalogUtils::ProxyProtocol;
65 string HttpdCatalogUtils::ProxyHost;
66 string HttpdCatalogUtils::ProxyUser;
67 string HttpdCatalogUtils::ProxyPassword;
68 string HttpdCatalogUtils::ProxyUserPW;
69 
70 int HttpdCatalogUtils::ProxyPort = 0;
71 int HttpdCatalogUtils::ProxyAuthType = 0;
72 bool HttpdCatalogUtils::useInternalCache = false;
73 
74 string HttpdCatalogUtils::NoProxyRegex;
75 
76 #define prolog string("HttpCatalogUtils::").append(__func__).append("() - ")
77 
78 // Initialization routine for the httpd_catalog_module for certain parameters
79 // and keys, like the white list, the MimeTypes translation.
80 void HttpdCatalogUtils::initialize()
81 {
82  // MimeTypes - translate from a mime type to a module name
83  bool found = false;
84  string key = HTTPD_CATALOG_MIMELIST;
85  vector<string> vals;
86  TheBESKeys::TheKeys()->get_values(key, vals, found);
87  if (found && vals.size()) {
88  vector<string>::iterator i = vals.begin();
89  vector<string>::iterator e = vals.end();
90  for (; i != e; i++) {
91  size_t colon = (*i).find(":");
92  if (colon == string::npos) {
93  string err = (string) "Malformed " + HTTPD_CATALOG_MIMELIST + " " + (*i) + " specified in the gateway configuration";
94  throw BESSyntaxUserError(err, __FILE__, __LINE__);
95  }
96  string mod = (*i).substr(0, colon);
97  string mime = (*i).substr(colon + 1);
98  MimeList[mod] = mime;
99  }
100  }
101 
102  found = false;
103  key = HTTPD_CATALOG_PROXYHOST;
104  TheBESKeys::TheKeys()->get_value(key, HttpdCatalogUtils::ProxyHost, found);
105  if (found && !HttpdCatalogUtils::ProxyHost.empty()) {
106  // if the proxy host is set, then check to see if the port is
107  // set. Does not need to be.
108  found = false;
109  key = HTTPD_CATALOG_PROXYPORT;
110  string port;
111  TheBESKeys::TheKeys()->get_value(key, port, found);
112  if (found && !port.empty()) {
113  HttpdCatalogUtils::ProxyPort = atoi(port.c_str());
114  if (!HttpdCatalogUtils::ProxyPort) {
115  string err = (string) "httpd catalog proxy host is specified, but specified port is absent";
116  throw BESSyntaxUserError(err, __FILE__, __LINE__);
117  }
118  }
119 
120  // @TODO Either use this or remove it - right now this variable is never used downstream
121  // find the protocol to use for the proxy server. If none set, default to http
122  found = false;
123  key = HTTPD_CATALOG_PROXYPROTOCOL;
124  TheBESKeys::TheKeys()->get_value(key, HttpdCatalogUtils::ProxyProtocol, found);
125  if (!found || HttpdCatalogUtils::ProxyProtocol.empty()) {
126  HttpdCatalogUtils::ProxyProtocol = "http";
127  }
128 
129  // find the user to use for authenticating with the proxy server. If none set,
130  // default to ""
131  found = false;
132  key = HTTPD_CATALOG_PROXYUSER;
133  TheBESKeys::TheKeys()->get_value(key, HttpdCatalogUtils::ProxyUser, found);
134  if (!found) {
135  HttpdCatalogUtils::ProxyUser = "";
136  }
137 
138  // find the password to use for authenticating with the proxy server. If none set,
139  // default to ""
140  found = false;
141  key = HTTPD_CATALOG_PROXYPASSWORD;
142  TheBESKeys::TheKeys()->get_value(key, HttpdCatalogUtils::ProxyPassword, found);
143  if (!found) {
144  HttpdCatalogUtils::ProxyPassword = "";
145  }
146 
147  // find the user:password string to use for authenticating with the proxy server. If none set,
148  // default to ""
149  found = false;
150  key = HTTPD_CATALOG_PROXYUSERPW;
151  TheBESKeys::TheKeys()->get_value(key, HttpdCatalogUtils::ProxyUserPW, found);
152  if (!found) {
153  HttpdCatalogUtils::ProxyUserPW = "";
154  }
155 
156  // find the authentication mechanism to use with the proxy server. If none set,
157  // default to BASIC authentication.
158  found = false;
159  key = HTTPD_CATALOG_PROXYAUTHTYPE;
160  string authType;
161  TheBESKeys::TheKeys()->get_value(key, authType, found);
162  if (found) {
163  authType = BESUtil::lowercase(authType);
164  if (authType == "basic") {
165  HttpdCatalogUtils::ProxyAuthType = CURLAUTH_BASIC;
166  BESDEBUG(MODULE, prolog << "ProxyAuthType BASIC set." << endl);
167  }
168  else if (authType == "digest") {
169  HttpdCatalogUtils::ProxyAuthType = CURLAUTH_DIGEST;
170  BESDEBUG(MODULE, prolog << "ProxyAuthType DIGEST set." << endl);
171  }
172 
173  else if (authType == "ntlm") {
174  HttpdCatalogUtils::ProxyAuthType = CURLAUTH_NTLM;
175  BESDEBUG(MODULE, prolog << "ProxyAuthType NTLM set." << endl);
176  }
177  else {
178  HttpdCatalogUtils::ProxyAuthType = CURLAUTH_BASIC;
179  BESDEBUG(MODULE,
180  prolog << "User supplied an invalid value '"<< authType << "' for Gateway.ProxyAuthType. Falling back to BASIC authentication scheme." << endl);
181  }
182  }
183  else {
184  HttpdCatalogUtils::ProxyAuthType = CURLAUTH_BASIC;
185  }
186  }
187 
188  found = false;
189  key = HTTPD_CATALOG_USE_INTERNAL_CACHE;
190  string use_cache;
191  TheBESKeys::TheKeys()->get_value(key, use_cache, found);
192  if (found) {
193  if (use_cache == "true" || use_cache == "TRUE" || use_cache == "True" || use_cache == "yes" || use_cache == "YES" || use_cache == "Yes")
194  HttpdCatalogUtils::useInternalCache = true;
195  else
196  HttpdCatalogUtils::useInternalCache = false;
197  }
198  else {
199  // If not set, default to false. Assume squid or ...
200  HttpdCatalogUtils::useInternalCache = false;
201  }
202  // Grab the value for the NoProxy regex; empty if there is none.
203  found = false; // Not used
204  TheBESKeys::TheKeys()->get_value("Gateway.NoProxy", HttpdCatalogUtils::NoProxyRegex, found);
205 }
206 
207 void HttpdCatalogUtils::get_type_from_disposition(const string &disp, string &type)
208 {
209  size_t fnpos = disp.find("filename");
210  if (fnpos != string::npos) {
211  // Got the filename attribute, now get the
212  // filename, which is after the pound sign (#)
213  size_t pos = disp.find("#", fnpos);
214  if (pos == string::npos) pos = disp.find("=", fnpos);
215  if (pos != string::npos) {
216  // Got the filename to the end of the
217  // string, now get it to either the end of
218  // the string or the start of the next
219  // attribute
220  string filename;
221  size_t sp = disp.find(" ", pos);
222  if (pos != string::npos) {
223  // space before the next attribute
224  filename = disp.substr(pos + 1, sp - pos - 1);
225  }
226  else {
227  // to the end of the string
228  filename = disp.substr(pos + 1);
229  }
230 
231  // now see if it's wrapped in quotes
232  if (filename[0] == '"') {
233  filename = filename.substr(1);
234  }
235  if (filename[filename.length() - 1] == '"') {
236  filename = filename.substr(0, filename.length() - 1);
237  }
238 
239  // we have the filename now, run it through
240  // the type match to get the file type.
241 
243  type = utils->get_handler_name(filename);
244  }
245  }
246 }
247 
248 void HttpdCatalogUtils::get_type_from_content_type(const string &ctype, string &type)
249 {
250  BESDEBUG(MODULE, prolog << "BEGIN" << endl);
251 
252  map<string, string>::iterator i = MimeList.begin();
253  map<string, string>::iterator e = MimeList.end();
254  bool done = false;
255  for (; i != e && !done; i++) {
256  BESDEBUG(MODULE, prolog << "Comparing content type '" << ctype << "' against mime list element '" << (*i).second << "'"<< endl);
257  BESDEBUG(MODULE, prolog << "first: " << (*i).first << " second: " << (*i).second << endl);
258 
259  if ((*i).second == ctype) {
260 
261  BESDEBUG(MODULE, prolog << "MATCH" << endl);
262 
263  type = (*i).first;
264  done = true;
265  }
266  }
267 
268  BESDEBUG(MODULE, prolog << "END" << endl);
269 }
270 
271 void HttpdCatalogUtils::get_type_from_url(const string &url, string &type)
272 {
273  const BESCatalogUtils *utils = BESCatalogList::TheCatalogList()->find_catalog("catalog")->get_catalog_utils();
274 
275  type = utils->get_handler_name(url);
276 }
277 
278 } // namespace httpd_catalog
279 
BESCatalogUtils
Definition: BESCatalogUtils.h:61
BESCatalogList::default_catalog
virtual BESCatalog * default_catalog() const
The the default catalog.
Definition: BESCatalogList.h:118
libdap
Definition: BESDapFunctionResponseCache.h:35
BESCatalogList::TheCatalogList
static BESCatalogList * TheCatalogList()
Get the singleton BESCatalogList instance.
Definition: BESCatalogList.cc:81
TheBESKeys::TheKeys
static TheBESKeys * TheKeys()
Definition: TheBESKeys.cc:62
BESCatalogUtils::get_handler_name
std::string get_handler_name(const std::string &item) const
Find the handler name that will process.
Definition: BESCatalogUtils.cc:422
BESSyntaxUserError
error thrown if there is a user syntax error in the request or any other user error
Definition: BESSyntaxUserError.h:41
BESCatalog::get_catalog_utils
virtual BESCatalogUtils * get_catalog_utils() const
Get a pointer to the utilities, customized for this catalog.
Definition: BESCatalog.h:113
TheBESKeys::get_value
void get_value(const std::string &s, std::string &val, bool &found)
Retrieve the value of a given key, if set.
Definition: TheBESKeys.cc:272
TheBESKeys::get_values
void get_values(const std::string &s, std::vector< std::string > &vals, bool &found)
Retrieve the values of a given key, if set.
Definition: TheBESKeys.cc:303
BESUtil::lowercase
static std::string lowercase(const std::string &s)
Definition: BESUtil.cc:200