mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 02:42:49 -04:00
451 lines
19 KiB
Plaintext
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();
|
|
}
|
|
}
|