bes  Updated for version 3.20.5
BESStreamResponseHandler.cc
1 // BESStreamResponseHandler.cc
2 
3 // This file is part of bes, A C++ back-end server implementation framework
4 // for the OPeNDAP Data Access Protocol.
5 
6 // Copyright (c) 2004-2009 University Corporation for Atmospheric Research
7 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
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 Foundatiion; 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 University Corporation for Atmospheric Research at
24 // 3080 Center Green Drive, Boulder, CO 80301
25 
26 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
27 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
28 //
29 // Authors:
30 // pwest Patrick West <pwest@ucar.edu>
31 // jgarcia Jose Garcia <jgarcia@ucar.edu>
32 
33 #include <unistd.h>
34 
35 #include <cerrno>
36 #include <iostream>
37 #include <fstream>
38 #include <string>
39 #include <cstring>
40 
41 using std::ifstream;
42 using std::ios;
43 using std::endl;
44 using std::string;
45 
46 #include "BESStreamResponseHandler.h"
47 #include "BESRequestHandlerList.h"
48 #include "BESForbiddenError.h"
49 #include "BESNotFoundError.h"
50 #include "BESInternalError.h"
51 #include "BESDataNames.h"
52 #include "BESContainer.h"
53 #include "BESDataHandlerInterface.h"
54 
55 #define BES_STREAM_BUFFER_SIZE 4096
56 
57 BESStreamResponseHandler::BESStreamResponseHandler(const string &name) :
58  BESResponseHandler(name)
59 {
60 }
61 
62 BESStreamResponseHandler::~BESStreamResponseHandler()
63 {
64 }
65 
66 extern volatile int bes_timeout; // defined in BESInterface. jhrg 1/24/17
67 
79 {
80  d_response_object = 0;
81 
82  // Hack. We put this here because the bes timeout period should not
83  // include the time it takes to send data for a file transfer response.
84  //
85  // An alternative would be to implement a BESTransmitter for the "get stream"
86  // operation and have that run from the call to BESInterface::transmist_data().
87  // pcw talks about that below.
88  // jhrg 1/24/17
89  if (bes_timeout != 0) {
90  bes_timeout = 0;
91  alarm(bes_timeout);
92  }
93 
94  // What if there is a special way to stream back a data file?
95  // Should we pass this off to the request handlers and put
96  // this code into a different class for reuse? For now
97  // just keep it here. pcw 10/11/06
98 
99  // I thought about putting this in the transmit method below
100  // but decided that this is like executing a non-buffered
101  // request, so kept it here. Plus the idea expressed above
102  // led me to leave the code in the execute method.
103  // pcw 10/11/06
104  if (dhi.containers.size() != 1) {
105  string err = (string) "Unable to stream file: " + "no container specified";
106  throw BESInternalError(err, __FILE__, __LINE__);
107  }
108 
109  dhi.first_container();
110  BESContainer *container = dhi.container;
111  string filename = container->access();
112  if (filename.empty()) {
113  string err = (string) "Unable to stream file: " + "filename not specified";
114  throw BESInternalError(err, __FILE__, __LINE__);
115  }
116 
117  int bytes = 0;
118  ifstream os;
119  os.open(filename.c_str(), ios::in);
120  int myerrno = errno;
121  if (!os) {
122  string serr = (string) "Unable to stream file because it cannot be opened. file: '" + filename + "' msg: ";
123  char *err = strerror(myerrno);
124  if (err)
125  serr += err;
126  else
127  serr += "Unknown error";
128 
129  // ENOENT means that the node wasn't found.
130  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
131  // Otherwise, access is being denied for some other reason
132  if (myerrno == ENOENT || myerrno == ENOTDIR) {
133  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
134  throw BESNotFoundError(serr, __FILE__, __LINE__);
135  }
136  // Not a 404? Then we'll go with the forbidden fruit theory...
137  throw BESForbiddenError(serr, __FILE__, __LINE__);
138  }
139 
140  int nbytes;
141  char block[BES_STREAM_BUFFER_SIZE];
142  os.read(block, sizeof block);
143  nbytes = os.gcount();
144  while (nbytes) {
145  bytes += nbytes;
146  dhi.get_output_stream().write((char*) block, nbytes);
147 
148  os.read(block, sizeof block);
149  nbytes = os.gcount();
150  }
151 
152  os.close();
153 }
154 
163 {
164  // The Data is transmitted when it is read, dumped to stdout, so there is nothing
165  // to transmit here.
166 }
167 
174 void BESStreamResponseHandler::dump(ostream &strm) const
175 {
176  strm << BESIndent::LMarg << "BESStreamResponseHandler::dump - (" << (void *) this << ")" << endl;
177  BESIndent::Indent();
179  BESIndent::UnIndent();
180 }
181 
183 BESStreamResponseHandler::BESStreamResponseBuilder(const string &name)
184 {
185  return new BESStreamResponseHandler(name);
186 }
187 
error thrown if the resource requested cannot be found
exception thrown if inernal error encountered
virtual void execute(BESDataHandlerInterface &r)
executes the command 'get file <filename>;' by streaming the specified file
virtual string access()=0
returns the true name of this container
virtual void dump(ostream &strm) const
dumps information about this object
handler object that knows how to create a specific response object
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &r)
transmit the file, streaming it back to the client
error thrown if the BES is not allowed to access the resource requested
Structure storing information used by the BES to handle the request.
void first_container()
set the container pointer to the first container in the containers list
A container is something that holds data. E.G., a netcdf file or a database entry.
Definition: BESContainer.h:68
virtual void dump(std::ostream &strm) const
dumps information about this object
BESContainer * container
pointer to current container in this interface