bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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 "BESForbiddenError.h"
49#include "BESNotFoundError.h"
50#include "BESInternalError.h"
51#include "BESContainer.h"
52#include "BESDataHandlerInterface.h"
53#include "BESUtil.h"
54#include "RequestServiceTimer.h"
55
56#define BES_STREAM_BUFFER_SIZE 4096
57
58#define MODULE "bes"
59#define prolog std::string("BESStreamResponseHandler::").append(__func__).append("() - ")
60
72{
73 d_response_object = nullptr;
74
75 // Verify the request hasn't exceeded bes_timeout, and disable timeout if allowed.
76 RequestServiceTimer::TheTimer()->throw_if_timeout_expired(prolog + "ERROR: bes-timeout expired before transmit", __FILE__, __LINE__);
78
79 // What if there is a special way to stream back a data file?
80 // Should we pass this off to the request handlers and put
81 // this code into a different class for reuse? For now
82 // just keep it here. pcw 10/11/06
83
84 // I thought about putting this in the transmit method below
85 // but decided that this is like executing a non-buffered
86 // request, so kept it here. Plus the idea expressed above
87 // led me to leave the code in the execute method.
88 // pcw 10/11/06
89 if (dhi.containers.size() != 1) {
90 throw BESInternalError("Unable to stream file: no container specified", __FILE__, __LINE__);
91 }
92
93 dhi.first_container();
94 BESContainer *container = dhi.container;
95 string filename = container->access();
96 if (filename.empty()) {
97 throw BESInternalError("Unable to stream file: filename not specified", __FILE__, __LINE__);
98 }
99
100 ifstream os;
101 os.open(filename.c_str(), ios::in);
102 int myerrno = errno;
103 if (!os) {
104 string serr = "Unable to stream file because it cannot be opened. file: '" + filename + "' msg: ";
105 char *err = strerror(myerrno);
106 serr += err ? err: "Unknown error";
107
108 // ENOENT means that the node wasn't found.
109 // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
110 // Otherwise, access is being denied for some other reason
111 if (myerrno == ENOENT || myerrno == ENOTDIR) {
112 // On some systems a file that doesn't exist returns ENOTDIR because: w.f.t?
113 throw BESNotFoundError(serr, __FILE__, __LINE__);
114 }
115 // Not a 404? Then we'll go with the forbidden fruit theory...
116 throw BESForbiddenError(serr, __FILE__, __LINE__);
117 }
118
119 std::streamsize nbytes;
120 char block[BES_STREAM_BUFFER_SIZE];
121 os.read(block, sizeof block); // read() returns the istream&
122 nbytes = os.gcount(); // gcount() returns the number of chars read above
123 while (nbytes) {
124 dhi.get_output_stream().write((char*) block, nbytes);
125 os.read(block, sizeof block);
126 nbytes = os.gcount();
127 }
128
129 os.close();
130}
131
140{
141 // The Data is transmitted when it is read, dumped to stdout, so there is nothing
142 // to transmit here.
143}
144
151void BESStreamResponseHandler::dump(ostream &strm) const
152{
153 strm << BESIndent::LMarg << "BESStreamResponseHandler::dump - (" << (void *) this << ")" << endl;
154 BESIndent::Indent();
156 BESIndent::UnIndent();
157}
158
160BESStreamResponseHandler::BESStreamResponseBuilder(const string &name)
161{
162 return new BESStreamResponseHandler(name);
163}
164
A container is something that holds data. E.G., a netcdf file or a database entry.
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
void dump(std::ostream &strm) const override
dumps information about this object
void execute(BESDataHandlerInterface &r) override
executes the command 'get file <filename>;' by streaming the specified file
void dump(std::ostream &strm) const override
dumps information about this object
void transmit(BESTransmitter *transmitter, BESDataHandlerInterface &r) override
transmit the file, streaming it back to the client
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:898
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...