|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// -*- mode: c++; c-basic-offset:4 -*-
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This file is part of libdap, A C++ implementation of the OPeNDAP Data
|
|
Packit |
a4aae4 |
// Access Protocol.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// Copyright (c) 2002,2003 OPeNDAP, Inc.
|
|
Packit |
a4aae4 |
// Author: James Gallagher <jgallagher@opendap.org>
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is free software; you can redistribute it and/or
|
|
Packit |
a4aae4 |
// modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License as published by the Free Software Foundation; either
|
|
Packit |
a4aae4 |
// version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// This library is distributed in the hope that it will be useful,
|
|
Packit |
a4aae4 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4aae4 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4aae4 |
// Lesser General Public License for more details.
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4aae4 |
// License along with this library; if not, write to the Free Software
|
|
Packit |
a4aae4 |
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
a4aae4 |
//
|
|
Packit |
a4aae4 |
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#ifndef http_response_h
|
|
Packit |
a4aae4 |
#define http_response_h
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <unistd.h>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <cstdio>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include <string>
|
|
Packit |
a4aae4 |
#include <iostream>
|
|
Packit |
a4aae4 |
#include <algorithm>
|
|
Packit |
a4aae4 |
#include <iterator>
|
|
Packit |
a4aae4 |
#include <vector>
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#include "Response.h"
|
|
Packit |
a4aae4 |
#include "util.h"
|
|
Packit |
a4aae4 |
#include "debug.h"
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
namespace libdap
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// defined in HTTPConnect.cc
|
|
Packit |
a4aae4 |
extern int dods_keep_temps;
|
|
Packit |
a4aae4 |
extern void close_temp(FILE *s, const string &name);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** Encapsulate an http response. Instead of directly returning the FILE
|
|
Packit |
a4aae4 |
pointer from which a response is read and vector of headers, return an
|
|
Packit |
a4aae4 |
instance of this object.
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@todo Maybe refactor so that the header parsing code is here and not in
|
|
Packit |
a4aae4 |
HTTPConnect? */
|
|
Packit |
a4aae4 |
class HTTPResponse : public Response
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
private:
|
|
Packit |
a4aae4 |
std::vector<std::string> *d_headers; // Response headers
|
|
Packit |
a4aae4 |
std::string d_file; // Temp file that holds response body
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
protected:
|
|
Packit |
a4aae4 |
/** @name Suppressed default methods */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
HTTPResponse();
|
|
Packit |
a4aae4 |
HTTPResponse(const HTTPResponse &rs);
|
|
Packit |
a4aae4 |
HTTPResponse &operator=(const HTTPResponse &);
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
public:
|
|
Packit |
a4aae4 |
/** Build an HTTPResponse object. An instance of this class is used to
|
|
Packit |
a4aae4 |
return an HTTP response (body and headers). If the response is really
|
|
Packit |
a4aae4 |
from a remote server, the current HTTP code stores the body in a
|
|
Packit |
a4aae4 |
temporary file and the headers in a vector<string> object. This class
|
|
Packit |
a4aae4 |
will delete those resources when its destructor is called. If the
|
|
Packit |
a4aae4 |
response does not have a temporary file that needs to be deleted (say
|
|
Packit |
a4aae4 |
it actually comes from a local cache or was read directly into
|
|
Packit |
a4aae4 |
memory), the temp file should be set to "".
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
@param s FILE * to the response. Read the response body from this
|
|
Packit |
a4aae4 |
stream.
|
|
Packit |
a4aae4 |
@param status The HTTP response status code.
|
|
Packit |
a4aae4 |
@param h Response headers. This class will delete the pointer when
|
|
Packit |
a4aae4 |
the instance that contains it is destroyed.
|
|
Packit |
a4aae4 |
@param temp_file Name a the temporary file that holds the response
|
|
Packit |
a4aae4 |
body; this file is deleted when this instance is deleted. */
|
|
Packit |
a4aae4 |
HTTPResponse(FILE *s, int status, std::vector<std::string> *h, const std::string &temp_file)
|
|
Packit |
a4aae4 |
: Response(s, status), d_headers(h), d_file(temp_file)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Headers: " << endl);
|
|
Packit |
a4aae4 |
DBGN(copy(d_headers->begin(), d_headers->end(),
|
|
Packit |
a4aae4 |
ostream_iterator<string>(cerr, "\n")));
|
|
Packit |
a4aae4 |
DBGN(cerr << "end of headers." << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* @brief Build a HTTPResponse using a cpp fstream
|
|
Packit |
a4aae4 |
* When working with DAP4 responses, use C++ streams for I/0.
|
|
Packit |
a4aae4 |
* @todo Decide on how the temp files fit into DAP4
|
|
Packit |
a4aae4 |
* @param s
|
|
Packit |
a4aae4 |
* @param status
|
|
Packit |
a4aae4 |
* @param h
|
|
Packit |
a4aae4 |
* @param temp_file
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
HTTPResponse(std::fstream *s, int status, std::vector<std::string> *h, const std::string &temp_file)
|
|
Packit |
a4aae4 |
: Response(s, status), d_headers(h), d_file(temp_file)
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Headers: " << endl);
|
|
Packit |
a4aae4 |
DBGN(copy(d_headers->begin(), d_headers->end(),
|
|
Packit |
a4aae4 |
ostream_iterator<string>(cerr, "\n")));
|
|
Packit |
a4aae4 |
DBGN(cerr << "end of headers." << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** When an instance is destroyed, free the temporary resources: the
|
|
Packit |
a4aae4 |
temp_file and headers are deleted. If the tmp file name is "", it is
|
|
Packit |
a4aae4 |
not deleted. */
|
|
Packit |
a4aae4 |
virtual ~HTTPResponse()
|
|
Packit |
a4aae4 |
{
|
|
Packit |
a4aae4 |
DBG(cerr << "Freeing HTTPConnect resources (" + d_file + ")... ");
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
// This can always be done - if the cpp_stream is null, delete has no effect;
|
|
Packit |
a4aae4 |
// if non-null in this class it was allocated in HTTPConnect::plain_fetch_url
|
|
Packit |
a4aae4 |
// (or caching_fetch_url when that's implemented)
|
|
Packit |
a4aae4 |
delete get_cpp_stream();
|
|
Packit |
a4aae4 |
set_cpp_stream(0);
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
if (!dods_keep_temps && !d_file.empty()) {
|
|
Packit |
a4aae4 |
if (get_stream()) {
|
|
Packit |
a4aae4 |
close_temp(get_stream(), d_file);
|
|
Packit |
a4aae4 |
set_stream(0);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
else {
|
|
Packit |
a4aae4 |
long res = unlink(d_file.c_str());
|
|
Packit |
a4aae4 |
if (res != 0) throw InternalErr(__FILE__, __LINE__, "!FAIL! " + long_to_string(res));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
delete d_headers;
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
DBGN(cerr << endl);
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/**
|
|
Packit |
a4aae4 |
* Build a new HTTPResponse object that works with C++ streams. Assume that
|
|
Packit |
a4aae4 |
* the FILE* references a disk file.
|
|
Packit |
a4aae4 |
* @return
|
|
Packit |
a4aae4 |
*/
|
|
Packit |
a4aae4 |
void transform_to_cpp() {
|
|
Packit |
a4aae4 |
// ~Response() will take care of closing the FILE*. A better version of this
|
|
Packit |
a4aae4 |
// code would not leave the FILE* open when it's not needed, but this implementation
|
|
Packit |
a4aae4 |
// can use the existing HTTPConnect and HTTPCache software with very minimal
|
|
Packit |
a4aae4 |
// (or no) modification. jhrg 11/8/13
|
|
Packit |
a4aae4 |
set_cpp_stream(new std::fstream(d_file.c_str(), std::ios::in|std::ios::binary));
|
|
Packit |
a4aae4 |
}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @name Accessors */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
virtual std::vector<std::string> *get_headers() const { return d_headers; }
|
|
Packit |
a4aae4 |
virtual std::string get_file() const { return d_file; }
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
/** @name Mutators */
|
|
Packit |
a4aae4 |
//@{
|
|
Packit |
a4aae4 |
virtual void set_headers(std::vector<std::string> *h) { d_headers = h; }
|
|
Packit |
a4aae4 |
virtual void set_file(const std::string &n) { d_file = n; }
|
|
Packit |
a4aae4 |
//@}
|
|
Packit |
a4aae4 |
};
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
} // namespace libdap
|
|
Packit |
a4aae4 |
|
|
Packit |
a4aae4 |
#endif // http_response_h
|