bes  Updated for version 3.20.8
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 using std::ostream;
46 
47 #include "BESStreamResponseHandler.h"
48 #include "BESRequestHandlerList.h"
49 #include "BESForbiddenError.h"
50 #include "BESNotFoundError.h"
51 #include "BESInternalError.h"
52 #include "BESDataNames.h"
53 #include "BESContainer.h"
54 #include "BESDataHandlerInterface.h"
55 
56 #define BES_STREAM_BUFFER_SIZE 4096
57 
58 BESStreamResponseHandler::BESStreamResponseHandler(const string &name) :
59  BESResponseHandler(name)
60 {
61 }
62 
63 BESStreamResponseHandler::~BESStreamResponseHandler()
64 {
65 }
66 
67 extern volatile int bes_timeout; // defined in BESInterface. jhrg 1/24/17
68 
80 {
81  d_response_object = 0;
82 
83  // Hack. We put this here because the bes timeout period should not
84  // include the time it takes to send data for a file transfer response.
85  //
86  // An alternative would be to implement a BESTransmitter for the "get stream"
87  // operation and have that run from the call to BESInterface::transmist_data().
88  // pcw talks about that below.
89  // jhrg 1/24/17
90  if (bes_timeout != 0) {
91  bes_timeout = 0;
92  alarm(bes_timeout);
93  }
94 
95  // What if there is a special way to stream back a data file?
96  // Should we pass this off to the request handlers and put
97  // this code into a different class for reuse? For now
98  // just keep it here. pcw 10/11/06
99 
100  // I thought about putting this in the transmit method below
101  // but decided that this is like executing a non-buffered
102  // request, so kept it here. Plus the idea expressed above
103  // led me to leave the code in the execute method.
104  // pcw 10/11/06
105  if (dhi.containers.size() != 1) {
106  string err = (string) "Unable to stream file: " + "no container specified";
107  throw BESInternalError(err, __FILE__, __LINE__);
108  }
109 
110  dhi.first_container();
111  BESContainer *container = dhi.container;
112  string filename = container->access();
113  if (filename.empty()) {
114  string err = (string) "Unable to stream file: " + "filename not specified";
115  throw BESInternalError(err, __FILE__, __LINE__);
116  }
117 
118  int bytes = 0;
119  ifstream os;
120  os.open(filename.c_str(), ios::in);
121  int myerrno = errno;
122  if (!os) {
123  string serr = (string) "Unable to stream file because it cannot be opened. file: '" + filename + "' msg: ";
124  char *err = strerror(myerrno);
125  if (err)
126  serr += err;
127  else
128  serr += "Unknown error";
129 
130  // ENOENT means that the node wasn't found.
131  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
132  // Otherwise, access is being denied for some other reason
133  if (myerrno == ENOENT || myerrno == ENOTDIR) {
134  // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
135  throw BESNotFoundError(serr, __FILE__, __LINE__);
136  }
137  // Not a 404? Then we'll go with the forbidden fruit theory...
138  throw BESForbiddenError(serr, __FILE__, __LINE__);
139  }
140 
141  int nbytes;
142  char block[BES_STREAM_BUFFER_SIZE];
143  os.read(block, sizeof block);
144  nbytes = os.gcount();
145  while (nbytes) {
146  bytes += nbytes;
147  dhi.get_output_stream().write((char*) block, nbytes);
148 
149  os.read(block, sizeof block);
150  nbytes = os.gcount();
151  }
152 
153  os.close();
154 }
155 
164 {
165  // The Data is transmitted when it is read, dumped to stdout, so there is nothing
166  // to transmit here.
167 }
168 
175 void BESStreamResponseHandler::dump(ostream &strm) const
176 {
177  strm << BESIndent::LMarg << "BESStreamResponseHandler::dump - (" << (void *) this << ")" << endl;
178  BESIndent::Indent();
180  BESIndent::UnIndent();
181 }
182 
184 BESStreamResponseHandler::BESStreamResponseBuilder(const string &name)
185 {
186  return new BESStreamResponseHandler(name);
187 }
188 
A container is something that holds data. E.G., a netcdf file or a database entry.
Definition: BESContainer.h:65
virtual std::string access()=0
returns the true name of this container
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
BESContainer * container
pointer to current container in this interface
error thrown if the BES is not allowed to access the resource requested
exception thrown if internal error encountered
error thrown if the resource requested cannot be found
handler object that knows how to create a specific response object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual void dump(std::ostream &strm) const
dumps information about this object
virtual void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &r)
transmit the file, streaming it back to the client
virtual void execute(BESDataHandlerInterface &r)
executes the command 'get file <filename>;' by streaming the specified file