bes Updated for version 3.20.13
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
41using std::ifstream;
42using std::ios;
43using std::endl;
44using std::string;
45using 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#include "BESUtil.h"
56#include "RequestServiceTimer.h"
57
58#define BES_STREAM_BUFFER_SIZE 4096
59
60#define MODULE "bes"
61#define prolog std::string("BESStreamResponseHandler::").append(__func__).append("() - ")
62
63BESStreamResponseHandler::BESStreamResponseHandler(const string &name) :
65{
66}
67
68BESStreamResponseHandler::~BESStreamResponseHandler()
69{
70}
71
72//extern volatile int bes_timeout; // defined in BESInterface. jhrg 1/24/17
73
85{
86 d_response_object = 0;
87
88
89 // Hack. We put this here because the bes timeout period should not
90 // include the time it takes to send data for a file transfer response.
91 //
92 // An alternative would be to implement a BESTransmitter for the "get stream"
93 // operation and have that run from the call to BESInterface::transmist_data().
94 // pcw talks about that below.
95 // jhrg 1/24/17
96#if 0
97 if (bes_timeout != 0) {
98 bes_timeout = 0;
99 alarm(bes_timeout);
100 }
101#endif
102 // Verify the request hasn't exceeded bes_timeout, and disable timeout if allowed.
103 RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
105
106 // What if there is a special way to stream back a data file?
107 // Should we pass this off to the request handlers and put
108 // this code into a different class for reuse? For now
109 // just keep it here. pcw 10/11/06
110
111 // I thought about putting this in the transmit method below
112 // but decided that this is like executing a non-buffered
113 // request, so kept it here. Plus the idea expressed above
114 // led me to leave the code in the execute method.
115 // pcw 10/11/06
116 if (dhi.containers.size() != 1) {
117 string err = (string) "Unable to stream file: " + "no container specified";
118 throw BESInternalError(err, __FILE__, __LINE__);
119 }
120
121 dhi.first_container();
122 BESContainer *container = dhi.container;
123 string filename = container->access();
124 if (filename.empty()) {
125 string err = (string) "Unable to stream file: " + "filename not specified";
126 throw BESInternalError(err, __FILE__, __LINE__);
127 }
128
129 int bytes = 0;
130 ifstream os;
131 os.open(filename.c_str(), ios::in);
132 int myerrno = errno;
133 if (!os) {
134 string serr = (string) "Unable to stream file because it cannot be opened. file: '" + filename + "' msg: ";
135 char *err = strerror(myerrno);
136 if (err)
137 serr += err;
138 else
139 serr += "Unknown error";
140
141 // ENOENT means that the node wasn't found.
142 // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
143 // Otherwise, access is being denied for some other reason
144 if (myerrno == ENOENT || myerrno == ENOTDIR) {
145 // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
146 throw BESNotFoundError(serr, __FILE__, __LINE__);
147 }
148 // Not a 404? Then we'll go with the forbidden fruit theory...
149 throw BESForbiddenError(serr, __FILE__, __LINE__);
150 }
151
152 int nbytes;
153 char block[BES_STREAM_BUFFER_SIZE];
154 os.read(block, sizeof block);
155 nbytes = os.gcount();
156 while (nbytes) {
157 bytes += nbytes;
158 dhi.get_output_stream().write((char*) block, nbytes);
159
160 os.read(block, sizeof block);
161 nbytes = os.gcount();
162 }
163
164 os.close();
165}
166
175{
176 // The Data is transmitted when it is read, dumped to stdout, so there is nothing
177 // to transmit here.
178}
179
186void BESStreamResponseHandler::dump(ostream &strm) const
187{
188 strm << BESIndent::LMarg << "BESStreamResponseHandler::dump - (" << (void *) this << ")" << endl;
189 BESIndent::Indent();
191 BESIndent::UnIndent();
192}
193
195BESStreamResponseHandler::BESStreamResponseBuilder(const string &name)
196{
197 return new BESStreamResponseHandler(name);
198}
199
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
static void conditional_timeout_cancel()
Checks if the timeout alarm should be canceled based on the value of the BES key BES....
Definition: BESUtil.cc:895
static RequestServiceTimer * TheTimer()
Return a pointer to a singleton timer instance. If an instance does not exist it will create and init...
void throw_if_timeout_expired(const std::string &message, const std::string &file, const int line)
Checks the RequestServiceTimer to determine if the time spent servicing the request at this point has...