OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
GatewayRequest.cc
Go to the documentation of this file.
1 // GatewayRequest.cc
2 
3 // -*- mode: c++; c-basic-offset:4 -*-
4 
5 // This file is part of gateway_module, A C++ module that can be loaded in to
6 // the OPeNDAP Back-End Server (BES) and is able to handle remote requests.
7 
8 // Copyright (c) 2002,2003 OPeNDAP, Inc.
9 // Author: Patrick West <pwest@ucar.edu>
10 //
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
26 
27 // (c) COPYRIGHT URI/MIT 1994-1999
28 // Please read the full copyright statement in the file COPYRIGHT_URI.
29 //
30 // Authors:
31 // pcw Patrick West <pwest@ucar.edu>
32 
33 #include <HTTPConnect.h>
34 #include <RCReader.h>
35 #include <Error.h>
36 #include <GNURegex.h>
37 
38 using namespace libdap ;
39 
40 #include <BESInternalError.h>
41 #include <BESSyntaxUserError.h>
42 #include <BESDebug.h>
43 #include <BESCatalogUtils.h>
44 #include <BESRegex.h>
45 
46 #include "GatewayRequest.h"
47 #include "GatewayError.h"
48 #include "GatewayUtils.h"
49 #include "config.h"
50 
63 HTTPResponse *
64 GatewayRequest::make_request( const string &url, string &type )
65 {
66  if( url.empty() )
67  {
68  string err = "Remote Request URL is empty" ;
69  throw BESInternalError( err, __FILE__, __LINE__ ) ;
70  }
71 
72  BESDEBUG( "gateway", "GatewayRequest::make_request" << endl );
73  BESDEBUG( "gateway", " request = " << url << endl );
74 
75  RCReader *rcr = RCReader::instance() ;
76 
77  // Don't set up the proxy server for URLs that match the 'NoProxy'
78  // regex set in the gateway.conf file.
79  bool configure_proxy = true;
80  // Don't create the regex if the string is empty
81  if (!GatewayUtils::NoProxyRegex.empty())
82  {
83  Regex r(GatewayUtils::NoProxyRegex.c_str());
84  if (r.match(url.c_str(), url.length()) != -1) {
85  BESDEBUG( "gateway", "Gateway found NoProxy match. Regex: " << GatewayUtils::NoProxyRegex << "; Url: " << url << endl );
86  configure_proxy = false;
87  }
88  }
89 
90  if (configure_proxy)
91  {
92  rcr->set_proxy_server_protocol(GatewayUtils::ProxyProtocol);
93  rcr->set_proxy_server_host(GatewayUtils::ProxyHost);
94  rcr->set_proxy_server_port(GatewayUtils::ProxyPort);
95  }
96 
97 
98  // GatewayUtils::useInternalCache defaults to false; use squid...
99  rcr->set_use_cache( GatewayUtils::useInternalCache ) ;
100  HTTPConnect connect( rcr ) ;
101  connect.set_cache_enabled( GatewayUtils::useInternalCache ) ;
102 
103  HTTPResponse *response = 0 ;
104  try
105  {
106  response = connect.fetch_url( url ) ;
107  }
108  catch( Error &e )
109  {
110  BESInternalError err( e.get_error_message(), __FILE__, __LINE__ ) ;
111  throw err ;
112  }
113  catch( ... )
114  {
115  string msg = (string)"Unknown exception fetching remote request "
116  + url ;
117  BESInternalError err( msg, __FILE__, __LINE__ ) ;
118  throw err ;
119  }
120 
121  if( !response )
122  {
123  string msg = (string)"Response empty fetching remote request " + url ;
124  BESInternalError err( msg, __FILE__, __LINE__ ) ;
125  throw err ;
126  }
127 
128  // A remote request is successful if we get data or if there is a
129  // failed response in the http header.
130  if( response->get_status() != 200 && response->get_status() != 304 )
131  {
132  BESDEBUG( "gateway", " request FAILED with status "
133  << response->get_status() << endl );
134 
135  // get the error information from the temporary file
136  string err ;
137  try
138  {
139  BESDEBUG( "gateway", " reading text error from response file "
140  << response->get_file() << endl );
141  GatewayError::read_error( response->get_file(), err, url ) ;
142  }
143  catch( ... )
144  {
145  err += "Unable to load the error text" ;
146  }
147 
148  // toss the response
149  delete response ;
150  response = 0 ;
151 
152  throw BESInternalError( err, __FILE__, __LINE__ ) ;
153  }
154 
155  if( type.empty() || type == "gateway" )
156  {
157  // make sure that the type is empty, and not gateway
158  type = "" ;
159 
160  // Try and figure out the file type first from the
161  // Content-Disposition in the http header response.
162  string disp ;
163  string ctype ;
164  vector<string> *hdrs = response->get_headers() ;
165  if( hdrs )
166  {
167  vector<string>::const_iterator i = hdrs->begin() ;
168  vector<string>::const_iterator e = hdrs->end() ;
169  for( ; i != e; i++ )
170  {
171  string hdr_line = (*i) ;
172  hdr_line = BESUtil::lowercase( hdr_line ) ;
173  if( hdr_line.find( "content-disposition" ) != string::npos )
174  {
175  // Content disposition exists
176  disp = hdr_line ;
177  }
178  if( hdr_line.find( "content-type" ) != string::npos )
179  {
180  ctype = hdr_line ;
181  }
182  }
183  }
184 
185  if( !disp.empty() )
186  {
187  // Content disposition exists, grab the filename
188  // attribute
190  BESDEBUG( "gateway", "Looked at disposition " << disp
191  << " for type, returned \"" << type
192  << "\"" << endl ) ;
193  }
194 
195  // still haven't figured out the type. Check the content-type
196  // next, translate to the BES module name. It's also possible
197  // that even though Content-disposition was available, we could
198  // not determine the type of the file.
199  if( type.empty() && !ctype.empty() )
200  {
202  BESDEBUG( "gateway", "Looked at content type " << ctype
203  << " for type, returned \"" << type
204  << "\"" << endl ) ;
205  }
206 
207  // still haven't figured out the type. Now check the actual URL
208  // and see if we can't match the URL to a module name
209  if( type.empty() )
210  {
211  GatewayUtils::Get_type_from_url( url, type ) ;
212  BESDEBUG( "gateway", "Looked at url " << url
213  << " for type, returned \"" << type
214  << "\"" << endl ) ;
215  }
216 
217  // still couldn't figure it out ... throw an exception
218  if( type.empty() )
219  {
220  string err = (string)"Unable to determine the type of data"
221  + " returned from " + url ;
222  throw BESSyntaxUserError( err, __FILE__, __LINE__ ) ;
223  }
224  }
225 
226  BESDEBUG( "gateway", "GatewayRequest::make_request - done" << endl );
227 
228  return response ;
229 }
230 
static void read_error(const string &filename, string &err, const string &url)
read the target response file that contains textual error information
Definition: GatewayError.cc:47
exception thrown if inernal error encountered
static string lowercase(const string &s)
Convert a string to all lower case.
Definition: BESUtil.cc:182
static string ProxyProtocol
Definition: GatewayUtils.h:52
static string NoProxyRegex
Definition: GatewayUtils.h:61
error thrown if there is a user syntax error in the request or any other user error ...
static class NCMLUtil overview
static string ProxyHost
Definition: GatewayUtils.h:53
static void Get_type_from_content_type(const string &ctype, string &type)
static void Get_type_from_disposition(const string &disp, string &type)
static int ProxyPort
Definition: GatewayUtils.h:57
HTTPResponse * make_request(const string &url, string &type)
make the remote request against the given information
static void Get_type_from_url(const string &url, string &type)
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
static bool useInternalCache
Definition: GatewayUtils.h:59