panda3d/panda/src/downloader/httpChannel.I
2002-10-17 17:12:40 +00:00

451 lines
19 KiB
Plaintext

// Filename: httpChannel.I
// Created by: drose (24Sep02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::is_valid
// Access: Published
// Description: Returns true if the last-requested document was
// successfully retrieved and is ready to be read, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
is_valid() const {
return (!_source.is_null() && _state != S_failure &&
(_status_code / 100) == 2);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_url
// Access: Published
// Description: Returns the URL that was used to retrieve the
// most recent document: whatever URL was last passed to
// get_document() or get_header(). If a redirect has
// transparently occurred, this will return the new,
// redirected URL (the actual URL at which the document
// was located).
////////////////////////////////////////////////////////////////////
INLINE const URLSpec &HTTPChannel::
get_url() const {
return _url;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_http_version
// Access: Published
// Description: Returns the HTTP version number returned by the
// server, as one of the HTTPClient enumerated types,
// e.g. HTTPClient::HV_11.
////////////////////////////////////////////////////////////////////
INLINE HTTPClient::HTTPVersion HTTPChannel::
get_http_version() const {
return _http_version;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_http_version_string
// Access: Published
// Description: Returns the HTTP version number returned by the
// server, formatted as a string, e.g. "HTTP/1.1".
////////////////////////////////////////////////////////////////////
INLINE const string &HTTPChannel::
get_http_version_string() const {
return _http_version_string;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_status_code
// Access: Published
// Description: Returns the HTML return code from the document
// retrieval request. This will be in the 200 range if
// the document is successfully retrieved, or some other
// value in the case of an error.
////////////////////////////////////////////////////////////////////
INLINE int HTTPChannel::
get_status_code() const {
return _status_code;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_status_string
// Access: Published
// Description: Returns the string as returned by the server
// describing the status code for humans. This may or
// may not be meaningful.
////////////////////////////////////////////////////////////////////
INLINE const string &HTTPChannel::
get_status_string() const {
return _status_string;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_realm
// Access: Published
// Description: If the document failed to connect because of a 401
// (Authorization required) or 407 (Proxy authorization
// required) error, this method should return the
// "realm" returned by the server in which the requested
// document must be authenticated. This string may be
// presented to the user to request an associated
// username and password (which then should be stored in
// HTTPClient::set_username()).
//
// If the document was retrieved successfully, or failed
// to connect for some other reason, this string will be
// empty. If it is empty even in the presence of a 401
// or 407 error, then the client code and the server do
// not have a common scheme for exchanging passwords.
////////////////////////////////////////////////////////////////////
INLINE const string &HTTPChannel::
get_realm() const {
return _realm;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_redirect
// Access: Published
// Description: If the document failed with a redirect code (300
// series), this will generally contain the new URL the
// server wants us to try. In many cases, the client
// will automatically follow redirects; if these are
// succesful the client will return a successful code
// and get_redirect() will return empty, but get_url()
// will return the new, redirected URL.
////////////////////////////////////////////////////////////////////
INLINE const URLSpec &HTTPChannel::
get_redirect() const {
return _redirect;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::set_persistent_connection
// Access: Published
// Description: Indicates whether the HTTPChannel should try to keep
// the connection to the server open and reuse that
// connection for multiple documents, or whether it
// should close the connection and open a new one for
// each request. Set this true to keep the connections
// around when possible, false to recycle them.
//
// It makes most sense to set this false when the
// HTTPChannel will be used only once to retrieve a
// single document, true when you will be using the same
// HTTPChannel object to retrieve multiple documents.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
set_persistent_connection(bool persistent_connection) {
_persistent_connection = persistent_connection;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_persistent_connection
// Access: Published
// Description: Returns whether the HTTPChannel should try to keep
// the connection to the server open and reuse that
// connection for multiple documents, or whether it
// should close the connection and open a new one for
// each request. See set_persistent_connection().
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
get_persistent_connection() const {
return _persistent_connection;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::set_download_throttle
// Access: Published
// Description: Specifies whether nonblocking downloads (via
// download_to_file() or download_to_ram()) will be
// limited so as not to use all available bandwidth.
//
// If this is true, when a download has been started on
// this channel it will be invoked no more frequently
// than get_max_updates_per_second(), and the total
// bandwidth used by the download will be no more than
// get_max_bytes_per_second(). If this is false,
// downloads will proceed as fast as the server can send
// the data.
//
// This only has effect on the nonblocking I/O methods
// like begin_document(), etc. The blocking methods
// like get_document() always use as much CPU and
// bandwidth as they can get.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
set_download_throttle(bool download_throttle) {
_download_throttle = download_throttle;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_download_throttle
// Access: Published
// Description: Returns whether the nonblocking downloads will be
// bandwidth-limited. See set_download_throttle().
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
get_download_throttle() const {
return _download_throttle;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::set_max_bytes_per_second
// Access: Published
// Description: When bandwidth throttling is in effect (see
// set_download_throttle()), this specifies the maximum
// number of bytes per second that may be consumed by
// this channel.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
set_max_bytes_per_second(double max_bytes_per_second) {
_max_bytes_per_second = max_bytes_per_second;
_bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_max_bytes_per_second
// Access: Published
// Description: Returns the maximum number of bytes per second that
// may be consumed by this channel when
// get_download_throttle() is true.
////////////////////////////////////////////////////////////////////
INLINE double HTTPChannel::
get_max_bytes_per_second() const {
return _max_bytes_per_second;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::set_max_updates_per_second
// Access: Published
// Description: When bandwidth throttling is in effect (see
// set_download_throttle()), this specifies the maximum
// number of times per second that run() will attempt to
// do any downloading at all.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
set_max_updates_per_second(double max_updates_per_second) {
nassertv(max_updates_per_second != 0.0f);
_max_updates_per_second = max_updates_per_second;
_seconds_per_update = 1.0f / _max_updates_per_second;
_bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_max_updates_per_second
// Access: Published
// Description: Returns the maximum number of times per second that
// run() will do anything at all, when
// get_download_throttle() is true.
////////////////////////////////////////////////////////////////////
INLINE double HTTPChannel::
get_max_updates_per_second() const {
return _max_updates_per_second;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_file_size
// Access: Published
// Description: Returns the size of the file, if it is known.
// Returns 0 if the file size is not known.
//
// If the file is dynamically generated, the size may
// not be available until a read has started
// (e.g. open_read_file() has been called); and even
// then it may increase as more of the file is read due
// to the nature of HTTP/1.1 requests which can change
// their minds midstream about how much data they're
// sending you.
////////////////////////////////////////////////////////////////////
INLINE size_t HTTPChannel::
get_file_size() const {
return _file_size;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::post_form
// Access: Published
// Description: Posts form data to a particular URL and retrieves the
// response.
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
post_form(const URLSpec &url, const string &body) {
begin_request("POST", url, body, false, 0, 0);
run();
return is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_document
// Access: Published
// Description: Opens the named document for reading, if available.
// Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
get_document(const URLSpec &url) {
begin_request("GET", url, string(), false, 0, 0);
run();
return is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_subdocument
// Access: Published
// Description: Retrieves only the specified byte range of the
// indicated document. If last_byte is 0, it stands for
// the last byte of the document. When a subdocument is
// requested, get_file_size() and get_bytes_downloaded()
// will report the number of bytes of the subdocument,
// not of the complete document.
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
get_subdocument(const URLSpec &url, size_t first_byte, size_t last_byte) {
begin_request("GET", url, string(), false, first_byte, last_byte);
run();
return is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_header
// Access: Published
// Description: Like get_document(), except only the header
// associated with the document is retrieved. This may
// be used to test for existence of the document; it
// might also return the size of the document (if the
// server gives us this information).
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
get_header(const URLSpec &url) {
begin_request("HEAD", url, string(), false, 0, 0);
run();
return is_valid();
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::begin_post_form
// Access: Published
// Description: Posts form data to a particular URL and retrieves the
// response, all using non-blocking I/O. See
// begin_document() and post_form().
//
// It is important to note that you *must* call run()
// repeatedly after calling this method until run()
// returns false, and you may not call any other
// document posting or retrieving methods using the
// HTTPChannel object in the interim, or your form data
// may not get posted.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
begin_post_form(const URLSpec &url, const string &body) {
begin_request("POST", url, body, true, 0, 0);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::begin_document
// Access: Published
// Description: Begins a non-blocking request to retrieve a given
// document. This method will return immediately, even
// before a connection to the server has necessarily
// been established; you must then call run() from time
// to time until the return value of run() is false.
// Then you may check is_valid() and get_status_code()
// to determine the status of your request.
//
// If a previous request had been pending, that request
// is discarded.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
begin_document(const URLSpec &url) {
begin_request("GET", url, string(), true, 0, 0);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::begin_subdocument
// Access: Published
// Description: Begins a non-blocking request to retrieve only the
// specified byte range of the indicated document. If
// last_byte is 0, it stands for the last byte of the
// document. When a subdocument is requested,
// get_file_size() and get_bytes_downloaded() will
// report the number of bytes of the subdocument, not of
// the complete document.
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
begin_subdocument(const URLSpec &url, size_t first_byte, size_t last_byte) {
begin_request("GET", url, string(), true, first_byte, last_byte);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::begin_header
// Access: Published
// Description: Begins a non-blocking request to retrieve a given
// header. See begin_document() and get_header().
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
begin_header(const URLSpec &url) {
begin_request("HEAD", url, string(), true, 0, 0);
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::get_bytes_downloaded
// Access: Published
// Description: Returns the number of bytes downloaded during the
// last (or current) download_to_file() or
// download_to_ram operation(). This can be used in
// conjunction with get_file_size() to report the
// percent complete (but be careful, since
// get_file_size() may return 0 if the server has not
// told us the size of the file).
////////////////////////////////////////////////////////////////////
INLINE size_t HTTPChannel::
get_bytes_downloaded() const {
return _bytes_downloaded;
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::is_download_complete
// Access: Published
// Description: Returns true when a download_to() or
// download_to_ram() has executed and the file has been
// fully downloaded. If this still returns false after
// processing has completed, there was an error in
// transmission.
////////////////////////////////////////////////////////////////////
INLINE bool HTTPChannel::
is_download_complete() const {
return (_download_dest != DD_none &&
(_state == S_read_body || _state == S_read_trailer));
}
////////////////////////////////////////////////////////////////////
// Function: HTTPChannel::check_socket
// Access: Private
// Description: Checks whether the connection to the server has been
// closed after a failed read. If it has, issues a
// warning and calls free_bio().
////////////////////////////////////////////////////////////////////
INLINE void HTTPChannel::
check_socket() {
nassertv(!_source.is_null());
if ((*_source)->is_closed()) {
if (downloader_cat.is_debug()) {
downloader_cat.debug()
<< "Lost connection to server unexpectedly during read.\n";
}
free_bio();
}
}