mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
reference-count sockets, prepare for non-blocking i/o
This commit is contained in:
parent
203a2dbda7
commit
cd7815bb88
@ -13,6 +13,8 @@
|
||||
#define SOURCES \
|
||||
config_downloader.h \
|
||||
asyncUtility.I asyncUtility.h \
|
||||
bioPtr.I bioPtr.h \
|
||||
bioStreamPtr.I bioStreamPtr.h \
|
||||
bioStream.I bioStream.h bioStreamBuf.h \
|
||||
chunkedStream.I chunkedStream.h chunkedStreamBuf.h \
|
||||
extractor.h \
|
||||
@ -21,6 +23,7 @@
|
||||
identityStream.I identityStream.h identityStreamBuf.h \
|
||||
multiplexStream.I multiplexStream.h \
|
||||
multiplexStreamBuf.I multiplexStreamBuf.h \
|
||||
socketStream.h socketStream.I \
|
||||
urlSpec.I urlSpec.h \
|
||||
$[if $[HAVE_NET], downloadDb.I downloadDb.h downloader.I downloader.h] \
|
||||
$[if $[HAVE_ZLIB], decompressor.h zcompressor.I zcompressor.h download_utils.h] \
|
||||
@ -29,6 +32,8 @@
|
||||
#define INCLUDED_SOURCES \
|
||||
config_downloader.cxx \
|
||||
asyncUtility.cxx \
|
||||
bioPtr.cxx \
|
||||
bioStreamPtr.cxx \
|
||||
bioStream.cxx bioStreamBuf.cxx \
|
||||
chunkedStream.cxx chunkedStreamBuf.cxx \
|
||||
extractor.cxx \
|
||||
@ -42,6 +47,8 @@
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
asyncUtility.h asyncUtility.I \
|
||||
bioPtr.I bioPtr.h \
|
||||
bioStreamPtr.I bioStreamPtr.h \
|
||||
bioStream.I bioStream.h bioStreamBuf.h \
|
||||
chunkedStream.I chunkedStream.h chunkedStreamBuf.h \
|
||||
config_downloader.h \
|
||||
@ -55,6 +62,7 @@
|
||||
multiplexStream.I multiplexStream.h \
|
||||
multiplexStreamBuf.I multiplexStreamBuf.I \
|
||||
patcher.h patcher.I \
|
||||
socketStream.h socketStream.I \
|
||||
urlSpec.h urlSpec.I \
|
||||
zcompressor.I zcompressor.h
|
||||
|
||||
|
77
panda/src/downloader/bioPtr.I
Normal file
77
panda/src/downloader/bioPtr.I
Normal file
@ -0,0 +1,77 @@
|
||||
// Filename: bioPtr.I
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: BioPtr::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BioPtr::
|
||||
BioPtr(BIO *bio) : _bio(bio) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::operator *
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BIO &BioPtr::
|
||||
operator *() const {
|
||||
return *_bio;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::operator ->
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BIO *BioPtr::
|
||||
operator ->() const {
|
||||
return _bio;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::operator typecast
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BioPtr::
|
||||
operator BIO * () const {
|
||||
return _bio;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::get_bio
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void BioPtr::
|
||||
set_bio(BIO *bio) {
|
||||
_bio = bio;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::get_bio
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BIO *BioPtr::
|
||||
get_bio() const {
|
||||
return _bio;
|
||||
}
|
84
panda/src/downloader/bioPtr.cxx
Normal file
84
panda/src/downloader/bioPtr.cxx
Normal file
@ -0,0 +1,84 @@
|
||||
// Filename: bioPtr.cxx
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "bioPtr.h"
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::Constructor
|
||||
// Access: Public
|
||||
// Description: This flavor of the constructor automatically creates
|
||||
// a socket BIO and feeds it the server and port name
|
||||
// from the indicated URL. It doesn't call
|
||||
// BIO_do_connect(), though.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BioPtr::
|
||||
BioPtr(const URLSpec &url) {
|
||||
_server_name = url.get_server();
|
||||
_port = url.get_port();
|
||||
_bio = BIO_new_connect((char *)_server_name.c_str());
|
||||
BIO_set_conn_int_port(_bio, &_port);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BioPtr::
|
||||
~BioPtr() {
|
||||
if (_bio != (BIO *)NULL) {
|
||||
if (downloader_cat.is_debug() && !_server_name.empty()) {
|
||||
downloader_cat.debug()
|
||||
<< "Dropping connection to " << _server_name << ":" << _port << "\n";
|
||||
}
|
||||
|
||||
BIO_free_all(_bio);
|
||||
_bio = (BIO *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioPtr::connect
|
||||
// Access: Public
|
||||
// Description: Calls BIO_do_connect() to establish a connection on
|
||||
// the previously-named server and port. Returns true
|
||||
// if successful, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool BioPtr::
|
||||
connect() const {
|
||||
nassertr(_bio != (BIO *)NULL && !_server_name.empty(), false);
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug()
|
||||
<< "Connecting to " << _server_name << ":" << _port << "\n";
|
||||
}
|
||||
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not connect to " << _server_name << ":" << _port << "\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
69
panda/src/downloader/bioPtr.h
Normal file
69
panda/src/downloader/bioPtr.h
Normal file
@ -0,0 +1,69 @@
|
||||
// Filename: bioPtr.h
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BIOPTR_H
|
||||
#define BIOPTR_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "referenceCount.h"
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class URLSpec;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : BioPtr
|
||||
// Description : A wrapper around an OpenSSL BIO object to make a
|
||||
// reference-counting pointer to it. It appears that
|
||||
// the OpenSSL library already uses reference counts on
|
||||
// these things internally, but the interface doesn't
|
||||
// appear to be public; so we might as well wrap the
|
||||
// whole thing at the high level.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS BioPtr : public ReferenceCount {
|
||||
public:
|
||||
INLINE BioPtr(BIO *bio);
|
||||
BioPtr(const URLSpec &url);
|
||||
virtual ~BioPtr();
|
||||
|
||||
INLINE BIO &operator *() const;
|
||||
INLINE BIO *operator -> () const;
|
||||
INLINE operator BIO * () const;
|
||||
|
||||
INLINE void set_bio(BIO *bio);
|
||||
INLINE BIO *get_bio() const;
|
||||
|
||||
bool connect() const;
|
||||
|
||||
private:
|
||||
BIO *_bio;
|
||||
string _server_name;
|
||||
int _port;
|
||||
};
|
||||
|
||||
#include "bioPtr.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream::
|
||||
IBioStream() : istream(&_buf) {
|
||||
IBioStream() : ISocketStream(&_buf) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -32,8 +32,8 @@ IBioStream() : istream(&_buf) {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream::
|
||||
IBioStream(BIO *source, bool owns_source) : istream(&_buf) {
|
||||
open(source, owns_source);
|
||||
IBioStream(BioPtr *source) : ISocketStream(&_buf) {
|
||||
open(source);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -42,9 +42,9 @@ IBioStream(BIO *source, bool owns_source) : istream(&_buf) {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream &IBioStream::
|
||||
open(BIO *source, bool owns_source) {
|
||||
open(BioPtr *source) {
|
||||
clear(0);
|
||||
_buf.open_read(source, owns_source);
|
||||
_buf.open_read(source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -17,3 +17,19 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "bioStream.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IBioStream::is_closed
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if the last eof condition was triggered
|
||||
// because the socket has genuinely closed, or false if
|
||||
// we can expect more data to come along shortly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool IBioStream::
|
||||
is_closed() {
|
||||
if (_buf._is_closed) {
|
||||
return true;
|
||||
}
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "socketStream.h"
|
||||
#include "bioStreamBuf.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -35,14 +36,16 @@
|
||||
//
|
||||
// Seeking is not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS IBioStream : public istream {
|
||||
class EXPCL_PANDAEXPRESS IBioStream : public ISocketStream {
|
||||
public:
|
||||
INLINE IBioStream();
|
||||
INLINE IBioStream(BIO *source, bool owns_source);
|
||||
INLINE IBioStream(BioPtr *source);
|
||||
|
||||
INLINE IBioStream &open(BIO *source, bool owns_source);
|
||||
INLINE IBioStream &open(BioPtr *source);
|
||||
INLINE IBioStream &close();
|
||||
|
||||
virtual bool is_closed();
|
||||
|
||||
private:
|
||||
BioStreamBuf _buf;
|
||||
};
|
||||
|
@ -32,8 +32,7 @@ typedef int streamsize;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BioStreamBuf::
|
||||
BioStreamBuf() {
|
||||
_source = (BIO *)NULL;
|
||||
_owns_source = false;
|
||||
_is_closed = false;
|
||||
|
||||
#ifdef WIN32_VC
|
||||
// In spite of the claims of the MSDN Library to the contrary,
|
||||
@ -67,9 +66,8 @@ BioStreamBuf::
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BioStreamBuf::
|
||||
open_read(BIO *source, bool owns_source) {
|
||||
open_read(BioPtr *source) {
|
||||
_source = source;
|
||||
_owns_source = owns_source;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -79,13 +77,7 @@ open_read(BIO *source, bool owns_source) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void BioStreamBuf::
|
||||
close_read() {
|
||||
if (_source != (BIO *)NULL) {
|
||||
if (_owns_source) {
|
||||
BIO_free_all(_source);
|
||||
_owns_source = false;
|
||||
}
|
||||
_source = (BIO *)NULL;
|
||||
}
|
||||
_source.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -105,11 +97,12 @@ underflow() {
|
||||
|
||||
// BIO_read might return -1 or -2 on eof or error, so we have to
|
||||
// allow for negative numbers.
|
||||
int read_count = BIO_read(_source, gptr(), buffer_size);
|
||||
int read_count = BIO_read(*_source, gptr(), buffer_size);
|
||||
|
||||
if (read_count != (int)num_bytes) {
|
||||
// Oops, we didn't read what we thought we would.
|
||||
if (read_count <= 0) {
|
||||
_is_closed = !BIO_should_retry(*_source);
|
||||
return EOF;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "bioPtr.h"
|
||||
#include "pointerTo.h"
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -36,15 +38,17 @@ public:
|
||||
BioStreamBuf();
|
||||
virtual ~BioStreamBuf();
|
||||
|
||||
void open_read(BIO *source, bool owns_source);
|
||||
void open_read(BioPtr *source);
|
||||
void close_read();
|
||||
|
||||
protected:
|
||||
virtual int underflow(void);
|
||||
|
||||
private:
|
||||
BIO *_source;
|
||||
bool _owns_source;
|
||||
PT(BioPtr) _source;
|
||||
bool _is_closed;
|
||||
|
||||
friend class IBioStream;
|
||||
};
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
77
panda/src/downloader/bioStreamPtr.I
Normal file
77
panda/src/downloader/bioStreamPtr.I
Normal file
@ -0,0 +1,77 @@
|
||||
// Filename: bioStreamPtr.I
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: BioStreamPtr::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BioStreamPtr::
|
||||
BioStreamPtr(IBioStream *stream) : _stream(stream) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::operator *
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream &BioStreamPtr::
|
||||
operator *() const {
|
||||
return *_stream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::operator ->
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream *BioStreamPtr::
|
||||
operator ->() const {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::operator typecast
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE BioStreamPtr::
|
||||
operator IBioStream * () const {
|
||||
return _stream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::get_stream
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void BioStreamPtr::
|
||||
set_stream(IBioStream *stream) {
|
||||
_stream = stream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::get_stream
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IBioStream *BioStreamPtr::
|
||||
get_stream() const {
|
||||
return _stream;
|
||||
}
|
36
panda/src/downloader/bioStreamPtr.cxx
Normal file
36
panda/src/downloader/bioStreamPtr.cxx
Normal file
@ -0,0 +1,36 @@
|
||||
// Filename: bioStreamPtr.cxx
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "bioPtr.h"
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: BioStreamPtr::Destructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
BioStreamPtr::
|
||||
~BioStreamPtr() {
|
||||
if (_stream != (IBioStream *)NULL) {
|
||||
delete _stream;
|
||||
_stream = (IBioStream *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
61
panda/src/downloader/bioStreamPtr.h
Normal file
61
panda/src/downloader/bioStreamPtr.h
Normal file
@ -0,0 +1,61 @@
|
||||
// Filename: bioStreamPtr.h
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BIOSTREAMPTR_H
|
||||
#define BIOSTREAMPTR_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "bioStream.h"
|
||||
#include "referenceCount.h"
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : BioStreamPtr
|
||||
// Description : A wrapper around an IBioStream object to make a
|
||||
// reference-counting pointer to it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS BioStreamPtr : public ReferenceCount {
|
||||
public:
|
||||
INLINE BioStreamPtr(IBioStream *stream);
|
||||
virtual ~BioStreamPtr();
|
||||
|
||||
INLINE IBioStream &operator *() const;
|
||||
INLINE IBioStream *operator -> () const;
|
||||
INLINE operator IBioStream * () const;
|
||||
|
||||
INLINE void set_stream(IBioStream *stream);
|
||||
INLINE IBioStream *get_stream() const;
|
||||
|
||||
bool connect() const;
|
||||
|
||||
private:
|
||||
IBioStream *_stream;
|
||||
};
|
||||
|
||||
#include "bioStreamPtr.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IChunkedStream::
|
||||
IChunkedStream() : istream(&_buf) {
|
||||
IChunkedStream() : ISocketStream(&_buf) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -32,9 +32,8 @@ IChunkedStream() : istream(&_buf) {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IChunkedStream::
|
||||
IChunkedStream(istream *source, bool owns_source,
|
||||
HTTPDocument *doc) : istream(&_buf) {
|
||||
open(source, owns_source, doc);
|
||||
IChunkedStream(BioStreamPtr *source, HTTPDocument *doc) : ISocketStream(&_buf) {
|
||||
open(source, doc);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -43,9 +42,9 @@ IChunkedStream(istream *source, bool owns_source,
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IChunkedStream &IChunkedStream::
|
||||
open(istream *source, bool owns_source, HTTPDocument *doc) {
|
||||
open(BioStreamPtr *source, HTTPDocument *doc) {
|
||||
clear(0);
|
||||
_buf.open_read(source, owns_source, doc);
|
||||
_buf.open_read(source, doc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -17,3 +17,24 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "chunkedStream.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IChunkedStream::is_closed
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if the last eof condition was triggered
|
||||
// because the socket has genuinely closed, or false if
|
||||
// we can expect more data to come along shortly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool IChunkedStream::
|
||||
is_closed() {
|
||||
if (_buf._done || (*_buf._source)->is_closed()) {
|
||||
return true;
|
||||
}
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
@ -21,9 +21,14 @@
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "socketStream.h"
|
||||
#include "chunkedStreamBuf.h"
|
||||
|
||||
class HTTPDocument;
|
||||
class BioStreamPtr;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : IChunkedStream
|
||||
@ -34,22 +39,24 @@ class HTTPDocument;
|
||||
// Seeking is not supported.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// No need to export from DLL.
|
||||
class IChunkedStream : public istream {
|
||||
class IChunkedStream : public ISocketStream {
|
||||
public:
|
||||
INLINE IChunkedStream();
|
||||
INLINE IChunkedStream(istream *source, bool owns_source,
|
||||
HTTPDocument *doc);
|
||||
INLINE IChunkedStream(BioStreamPtr *source, HTTPDocument *doc);
|
||||
|
||||
INLINE IChunkedStream &open(istream *source, bool owns_source,
|
||||
HTTPDocument *doc);
|
||||
INLINE IChunkedStream &open(BioStreamPtr *source, HTTPDocument *doc);
|
||||
INLINE IChunkedStream &close();
|
||||
|
||||
virtual bool is_closed();
|
||||
|
||||
private:
|
||||
ChunkedStreamBuf _buf;
|
||||
};
|
||||
|
||||
#include "chunkedStream.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include "chunkedStreamBuf.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#ifndef HAVE_STREAMSIZE
|
||||
// Some compilers (notably SGI) don't define this for us
|
||||
typedef int streamsize;
|
||||
@ -30,8 +33,6 @@ typedef int streamsize;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ChunkedStreamBuf::
|
||||
ChunkedStreamBuf() {
|
||||
_source = (istream *)NULL;
|
||||
_owns_source = false;
|
||||
_chunk_remaining = 0;
|
||||
_done = true;
|
||||
|
||||
@ -69,9 +70,8 @@ ChunkedStreamBuf::
|
||||
// from the chunked encoding.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ChunkedStreamBuf::
|
||||
open_read(istream *source, bool owns_source, HTTPDocument *doc) {
|
||||
open_read(BioStreamPtr *source, HTTPDocument *doc) {
|
||||
_source = source;
|
||||
_owns_source = owns_source;
|
||||
_chunk_remaining = 0;
|
||||
_done = false;
|
||||
_doc = doc;
|
||||
@ -94,13 +94,7 @@ open_read(istream *source, bool owns_source, HTTPDocument *doc) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void ChunkedStreamBuf::
|
||||
close_read() {
|
||||
if (_source != (istream *)NULL) {
|
||||
if (_owns_source) {
|
||||
delete _source;
|
||||
_owns_source = false;
|
||||
}
|
||||
_source = (istream *)NULL;
|
||||
}
|
||||
_source.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -151,15 +145,15 @@ read_chars(char *start, size_t length) {
|
||||
if (_chunk_remaining != 0) {
|
||||
// Extract some of the bytes remaining in the chunk.
|
||||
length = min(length, _chunk_remaining);
|
||||
_source->read(start, length);
|
||||
length = _source->gcount();
|
||||
(*_source)->read(start, length);
|
||||
length = (*_source)->gcount();
|
||||
_chunk_remaining -= length;
|
||||
return length;
|
||||
}
|
||||
|
||||
// Read the next chunk.
|
||||
string line;
|
||||
getline(*_source, line);
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
@ -180,3 +174,5 @@ read_chars(char *start, size_t length) {
|
||||
_chunk_remaining = chunk_size;
|
||||
return read_chars(start, length);
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
@ -20,7 +20,12 @@
|
||||
#define CHUNKEDSTREAMBUF_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "httpDocument.h"
|
||||
#include "bioStreamPtr.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -34,7 +39,7 @@ public:
|
||||
ChunkedStreamBuf();
|
||||
virtual ~ChunkedStreamBuf();
|
||||
|
||||
void open_read(istream *source, bool owns_source, HTTPDocument *doc);
|
||||
void open_read(BioStreamPtr *source, HTTPDocument *doc);
|
||||
void close_read();
|
||||
|
||||
protected:
|
||||
@ -43,13 +48,16 @@ protected:
|
||||
private:
|
||||
size_t read_chars(char *start, size_t length);
|
||||
|
||||
istream *_source;
|
||||
bool _owns_source;
|
||||
PT(BioStreamPtr) _source;
|
||||
size_t _chunk_remaining;
|
||||
bool _done;
|
||||
|
||||
PT(HTTPDocument) _doc;
|
||||
int _read_index;
|
||||
|
||||
friend class IChunkedStream;
|
||||
};
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "config_downloader.cxx"
|
||||
#include "asyncUtility.cxx"
|
||||
#include "bioPtr.cxx"
|
||||
#include "bioStreamPtr.cxx"
|
||||
#include "bioStream.cxx"
|
||||
#include "bioStreamBuf.cxx"
|
||||
#include "chunkedStream.cxx"
|
||||
|
@ -286,7 +286,7 @@ clear_expected_servers() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPClient::get_documents
|
||||
// Function: HTTPClient::make_channel
|
||||
// Access: Published
|
||||
// Description: Returns a new HTTPDocument object that may be used
|
||||
// for reading multiple documents using the same
|
||||
@ -295,12 +295,28 @@ clear_expected_servers() {
|
||||
// thus forcing a new connection for each document).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(HTTPDocument) HTTPClient::
|
||||
get_documents() {
|
||||
make_channel() {
|
||||
PT(HTTPDocument) doc = new HTTPDocument(this);
|
||||
doc->set_persistent_connection(true);
|
||||
return doc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPClient::post_form
|
||||
// Access: Published
|
||||
// Description: Posts form data to a particular URL and retrieves the
|
||||
// response. Returns a new HTTPDocument object whether
|
||||
// the document is successfully read or not; you can
|
||||
// test is_valid() and get_return_code() to determine
|
||||
// whether the document was retrieved.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(HTTPDocument) HTTPClient::
|
||||
post_form(const URLSpec &url, const string &body) {
|
||||
PT(HTTPDocument) doc = new HTTPDocument(this);
|
||||
doc->post_form(url, body);
|
||||
return doc;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPClient::get_document
|
||||
// Access: Published
|
||||
@ -314,7 +330,11 @@ get_documents() {
|
||||
PT(HTTPDocument) HTTPClient::
|
||||
get_document(const URLSpec &url, const string &body) {
|
||||
PT(HTTPDocument) doc = new HTTPDocument(this);
|
||||
doc->get_document(url, body);
|
||||
if (body.empty()) {
|
||||
doc->get_document(url);
|
||||
} else {
|
||||
doc->post_form(url, body);
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
|
||||
@ -322,10 +342,10 @@ get_document(const URLSpec &url, const string &body) {
|
||||
// Function: HTTPClient::get_header
|
||||
// Access: Published
|
||||
// Description: Like get_document(), except only the header
|
||||
// associated with the file is retrieved. This may be
|
||||
// used to test for existence of the file; it might also
|
||||
// return the size of the file (if the server gives us
|
||||
// this information).
|
||||
// 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).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(HTTPDocument) HTTPClient::
|
||||
get_header(const URLSpec &url) {
|
||||
|
@ -89,7 +89,8 @@ PUBLISHED:
|
||||
bool add_expected_server(const string &server_attributes);
|
||||
void clear_expected_servers();
|
||||
|
||||
PT(HTTPDocument) get_documents();
|
||||
PT(HTTPDocument) make_channel();
|
||||
PT(HTTPDocument) post_form(const URLSpec &url, const string &body);
|
||||
PT(HTTPDocument) get_document(const URLSpec &url,
|
||||
const string &body = string());
|
||||
PT(HTTPDocument) get_header(const URLSpec &url);
|
||||
|
@ -25,8 +25,7 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool HTTPDocument::
|
||||
is_valid() const {
|
||||
return (_source != (IBioStream *)NULL &&
|
||||
(_status_code / 100) == 2);
|
||||
return (!_source.is_null() && (_status_code / 100) == 2);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -183,30 +182,35 @@ get_file_size() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::get_document
|
||||
// Function: HTTPDocument::post_form
|
||||
// Access: Published
|
||||
// Description: Opens the named document for reading, or if body is
|
||||
// nonempty, posts data for a particular URL and
|
||||
// retrieves the response.
|
||||
// Description: Posts form data to a particular URL and retrieves the
|
||||
// response.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool HTTPDocument::
|
||||
get_document(const URLSpec &url, const string &body) {
|
||||
const char *method = "GET";
|
||||
if (!body.empty()) {
|
||||
method = "POST";
|
||||
}
|
||||
post_form(const URLSpec &url, const string &body) {
|
||||
return send_request("POST", url, body);
|
||||
}
|
||||
|
||||
return send_request(method, url, body);
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::get_document
|
||||
// Access: Published
|
||||
// Description: Opens the named document for reading, if available.
|
||||
// Returns true if successful, false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool HTTPDocument::
|
||||
get_document(const URLSpec &url) {
|
||||
return send_request("GET", url, string());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::get_header
|
||||
// Access: Published
|
||||
// Description: Like get_document(), except only the header
|
||||
// associated with the file is retrieved. This may be
|
||||
// used to test for existence of the file; it might also
|
||||
// return the size of the file (if the server gives us
|
||||
// this information).
|
||||
// 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 HTTPDocument::
|
||||
get_header(const URLSpec &url) {
|
||||
|
@ -43,12 +43,9 @@ static const char base64_table[64] = {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
HTTPDocument::
|
||||
HTTPDocument(HTTPClient *client, BIO *bio) :
|
||||
_client(client),
|
||||
_bio(bio)
|
||||
HTTPDocument(HTTPClient *client) :
|
||||
_client(client)
|
||||
{
|
||||
_owns_bio = false;
|
||||
_source = (IBioStream *)NULL;
|
||||
_persistent_connection = false;
|
||||
_state = S_new;
|
||||
_read_index = 0;
|
||||
@ -77,13 +74,13 @@ send_request(const string &method, const URLSpec &url, const string &body) {
|
||||
// Let's call this before we call make_header(), so we'll get the
|
||||
// right HTTP version and proxy information etc.
|
||||
set_url(url);
|
||||
if (!prepare_for_next()) {
|
||||
if (!prepare_for_next(true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string header;
|
||||
make_header(header, method, url, body);
|
||||
send_request(header, body);
|
||||
send_request(header, body, true);
|
||||
|
||||
if ((get_status_code() / 100) == 3 && get_status_code() != 305) {
|
||||
// Redirect. Should we handle it automatically?
|
||||
@ -103,9 +100,9 @@ send_request(const string &method, const URLSpec &url, const string &body) {
|
||||
new_url.set_username(url.get_username());
|
||||
}
|
||||
set_url(new_url);
|
||||
if (prepare_for_next()) {
|
||||
if (prepare_for_next(true)) {
|
||||
make_header(header, method, new_url, body);
|
||||
send_request(header, body);
|
||||
send_request(header, body, true);
|
||||
keep_going =
|
||||
((get_status_code() / 100) == 3 && get_status_code() != 305);
|
||||
}
|
||||
@ -125,8 +122,8 @@ send_request(const string &method, const URLSpec &url, const string &body) {
|
||||
// that have already been defined.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
send_request(const string &header, const string &body) {
|
||||
if (prepare_for_next()) {
|
||||
send_request(const string &header, const string &body, bool allow_reconnect) {
|
||||
if (prepare_for_next(allow_reconnect)) {
|
||||
// Tack on a proxy authorization if it is called for. Assume we
|
||||
// can use the same authorization we used last time.
|
||||
string proxy_auth_header = header;
|
||||
@ -149,7 +146,7 @@ send_request(const string &header, const string &body) {
|
||||
proxy_auth_header += "Proxy-Authorization: ";
|
||||
proxy_auth_header += _client->_proxy_authorization;
|
||||
proxy_auth_header += "\r\n";
|
||||
if (prepare_for_next()) {
|
||||
if (prepare_for_next(allow_reconnect)) {
|
||||
issue_request(proxy_auth_header, body);
|
||||
}
|
||||
}
|
||||
@ -165,7 +162,7 @@ send_request(const string &header, const string &body) {
|
||||
web_auth_header += "Authorization: ";
|
||||
web_auth_header += authorization;
|
||||
web_auth_header += "\r\n";
|
||||
if (prepare_for_next()) {
|
||||
if (prepare_for_next(allow_reconnect)) {
|
||||
issue_request(web_auth_header, body);
|
||||
}
|
||||
}
|
||||
@ -254,11 +251,7 @@ will_close_connection() const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
istream *HTTPDocument::
|
||||
open_read_file() const {
|
||||
// TODO: make this smarter about reference-counting the source
|
||||
// stream properly so we can return an istream and not worry about
|
||||
// future interference to or from the HTTPDocument.
|
||||
bool persist = (get_persistent_connection() && !will_close_connection());
|
||||
return ((HTTPDocument *)this)->read_body(!persist);
|
||||
return ((HTTPDocument *)this)->read_body();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -291,6 +284,45 @@ write_headers(ostream &out) const {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::read_body
|
||||
// Access: Published
|
||||
// Description: Returns a newly-allocated istream suitable for
|
||||
// reading the body of the document.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ISocketStream *HTTPDocument::
|
||||
read_body() {
|
||||
if (_state != S_read_header) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string transfer_coding = downcase(get_header_value("Transfer-Encoding"));
|
||||
string content_length = get_header_value("Content-Length");
|
||||
|
||||
ISocketStream *result;
|
||||
if (transfer_coding == "chunked") {
|
||||
// "chunked" transfer encoding. This means we will have to decode
|
||||
// the length of the file as we read it in chunks. The
|
||||
// IChunkedStream does this.
|
||||
_file_size = 0;
|
||||
_state = S_started_body;
|
||||
_read_index++;
|
||||
result = new IChunkedStream(_source, (HTTPDocument *)this);
|
||||
|
||||
} else {
|
||||
// If the transfer encoding is anything else, assume "identity".
|
||||
// This is just the literal characters following the header, up
|
||||
// until _file_size bytes have been read (if content-length was
|
||||
// specified), or till end of file otherwise.
|
||||
_state = S_started_body;
|
||||
_read_index++;
|
||||
result = new IIdentityStream(_source, (HTTPDocument *)this,
|
||||
!content_length.empty(), _file_size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::establish_connection
|
||||
// Access: Private
|
||||
@ -302,8 +334,6 @@ write_headers(ostream &out) const {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
establish_connection() {
|
||||
nassertr(_bio == (BIO *)NULL, false);
|
||||
|
||||
bool result;
|
||||
if (_proxy.empty()) {
|
||||
if (_url.get_scheme() == "https") {
|
||||
@ -330,25 +360,9 @@ establish_connection() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
establish_http() {
|
||||
ostringstream server;
|
||||
server << _url.get_server() << ":" << _url.get_port();
|
||||
string server_str = server.str();
|
||||
|
||||
_bio = BIO_new_connect((char *)server_str.c_str());
|
||||
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug() << "connecting to " << server_str << "\n";
|
||||
}
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not contact server " << server_str << "\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
_bio = new BioPtr(_url);
|
||||
_source = new BioStreamPtr(new IBioStream(_bio));
|
||||
return _bio->connect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -359,21 +373,9 @@ establish_http() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
establish_https() {
|
||||
ostringstream server;
|
||||
server << _url.get_server() << ":" << _url.get_port();
|
||||
string server_str = server.str();
|
||||
|
||||
_bio = BIO_new_connect((char *)server_str.c_str());
|
||||
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug() << "connecting to " << server_str << "\n";
|
||||
}
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not contact server " << server_str << "\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
_bio = new BioPtr(_url);
|
||||
_source = new BioStreamPtr(new IBioStream(_bio));
|
||||
if (!_bio->connect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -388,26 +390,9 @@ establish_https() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
establish_http_proxy() {
|
||||
ostringstream proxy_server;
|
||||
proxy_server << _proxy.get_server() << ":" << _proxy.get_port();
|
||||
string proxy_server_str = proxy_server.str();
|
||||
|
||||
_bio = BIO_new_connect((char *)proxy_server_str.c_str());
|
||||
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug()
|
||||
<< "connecting to proxy " << proxy_server_str << "\n";
|
||||
}
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not contact proxy " << proxy_server_str << "\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
_bio = new BioPtr(_proxy);
|
||||
_source = new BioStreamPtr(new IBioStream(_bio));
|
||||
return _bio->connect();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -419,13 +404,10 @@ establish_http_proxy() {
|
||||
bool HTTPDocument::
|
||||
establish_https_proxy() {
|
||||
// First, ask the proxy to open a connection for us.
|
||||
ostringstream proxy_server;
|
||||
proxy_server << _proxy.get_server() << ":" << _proxy.get_port();
|
||||
string proxy_server_str = proxy_server.str();
|
||||
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug()
|
||||
<< "connecting to proxy " << proxy_server_str << "\n";
|
||||
_bio = new BioPtr(_proxy);
|
||||
_source = new BioStreamPtr(new IBioStream(_bio));
|
||||
if (!_bio->connect()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ostringstream request;
|
||||
@ -438,54 +420,28 @@ establish_https_proxy() {
|
||||
}
|
||||
string connect_header = request.str();
|
||||
|
||||
_bio = BIO_new_connect((char *)proxy_server_str.c_str());
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not contact proxy " << proxy_server_str << ".\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now issue the request and read the response from the proxy.
|
||||
|
||||
// Temporarily flag our bio as being owned externally, so our call
|
||||
// to send_request() won't end up with a recursive call back to
|
||||
// establish_connection().
|
||||
_owns_bio = false;
|
||||
|
||||
string old_proxy_authorization = _client->_proxy_authorization;
|
||||
bool connected = send_request(connect_header, string());
|
||||
bool connected = send_request(connect_header, string(), false);
|
||||
if (!connected && get_status_code() == 407 &&
|
||||
_client->_proxy_authorization != old_proxy_authorization) {
|
||||
// If we ended up with a 407 (proxy authorization required), and
|
||||
// we changed authorization strings recently, then try the new
|
||||
// authorization string, once. (Normally, send_request() would
|
||||
// have tried it again automatically, but we may have prevented
|
||||
// that by setting _owns_bio to false.)
|
||||
if (!prepare_for_next()) {
|
||||
// that by passing false allow_reconnect as false.)
|
||||
if (!prepare_for_next(true)) {
|
||||
free_bio();
|
||||
_bio = BIO_new_connect((char *)proxy_server_str.c_str());
|
||||
if (BIO_do_connect(_bio) <= 0) {
|
||||
downloader_cat.info()
|
||||
<< "Could not contact proxy " << proxy_server_str
|
||||
<< " a second time.\n";
|
||||
#ifdef REPORT_SSL_ERRORS
|
||||
ERR_print_errors_fp(stderr);
|
||||
#endif
|
||||
_owns_bio = true;
|
||||
_bio = new BioPtr(_proxy);
|
||||
_source = new BioStreamPtr(new IBioStream(_bio));
|
||||
if (!_bio->connect()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
connected = send_request(connect_header, string());
|
||||
connected = send_request(connect_header, string(), false);
|
||||
}
|
||||
|
||||
// Now that we've connected, be honest with the _owns_bio flag: if
|
||||
// we're here, we know we really do own the BIO pointer (we just
|
||||
// created it, after all.)
|
||||
_owns_bio = true;
|
||||
|
||||
if (!connected) {
|
||||
downloader_cat.info()
|
||||
<< "proxy would not open connection to " << _url.get_authority()
|
||||
@ -538,7 +494,7 @@ establish_https_proxy() {
|
||||
bool HTTPDocument::
|
||||
make_https_connection() {
|
||||
BIO *sbio = BIO_new_ssl(_client->_ssl_ctx, true);
|
||||
BIO_push(sbio, _bio);
|
||||
BIO_push(sbio, *_bio);
|
||||
|
||||
SSL *ssl;
|
||||
BIO_get_ssl(sbio, &ssl);
|
||||
@ -563,7 +519,7 @@ make_https_connection() {
|
||||
|
||||
// Now that we've made an SSL handshake, we can use the SSL bio to
|
||||
// do all of our communication henceforth.
|
||||
_bio = sbio;
|
||||
_bio->set_bio(sbio);
|
||||
|
||||
long verify_result = SSL_get_verify_result(ssl);
|
||||
if (verify_result == X509_V_ERR_CERT_HAS_EXPIRED) {
|
||||
@ -995,7 +951,7 @@ set_url(const URLSpec &url) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HTTPDocument::
|
||||
issue_request(const string &header, const string &body) {
|
||||
if (_bio != (BIO *)NULL) {
|
||||
if (!_bio.is_null()) {
|
||||
string request = header;
|
||||
request += "\r\n";
|
||||
request += body;
|
||||
@ -1004,21 +960,21 @@ issue_request(const string &header, const string &body) {
|
||||
show_send(request);
|
||||
}
|
||||
#endif
|
||||
BIO_puts(_bio, request.c_str());
|
||||
BIO_puts(*_bio, request.c_str());
|
||||
read_http_response();
|
||||
|
||||
if (_source->eof() || _source->fail()) {
|
||||
if ((*_source)->eof() || (*_source)->fail()) {
|
||||
if (downloader_cat.is_debug()) {
|
||||
downloader_cat.debug()
|
||||
<< "Whoops, socket closed.\n";
|
||||
free_bio();
|
||||
if (prepare_for_next()) {
|
||||
if (prepare_for_next(true)) {
|
||||
#ifndef NDEBUG
|
||||
if (downloader_cat.is_spam()) {
|
||||
show_send(request);
|
||||
}
|
||||
#endif
|
||||
BIO_puts(_bio, request.c_str());
|
||||
BIO_puts(*_bio, request.c_str());
|
||||
read_http_response();
|
||||
}
|
||||
}
|
||||
@ -1035,14 +991,13 @@ issue_request(const string &header, const string &body) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HTTPDocument::
|
||||
read_http_response() {
|
||||
nassertv(_source != (IBioStream *)NULL);
|
||||
_headers.clear();
|
||||
_realm = string();
|
||||
|
||||
// The first line back should include the HTTP version and the
|
||||
// result code.
|
||||
string line;
|
||||
getline(*_source, line);
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
@ -1050,7 +1005,7 @@ read_http_response() {
|
||||
downloader_cat.spam() << "recv: " << line << "\n";
|
||||
}
|
||||
|
||||
if (!(*_source) || line.length() < 5 || line.substr(0, 5) != "HTTP/") {
|
||||
if (!(**_source) || line.length() < 5 || line.substr(0, 5) != "HTTP/") {
|
||||
// Not an HTTP response.
|
||||
_status_code = 0;
|
||||
_status_string = "Not an HTTP response";
|
||||
@ -1085,7 +1040,7 @@ read_http_response() {
|
||||
string field_name;
|
||||
string field_value;
|
||||
|
||||
getline(*_source, line);
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
@ -1093,7 +1048,7 @@ read_http_response() {
|
||||
downloader_cat.spam() << "recv: " << line << "\n";
|
||||
}
|
||||
|
||||
while (!_source->eof() && !_source->fail() && !line.empty()) {
|
||||
while (!(*_source)->eof() && !(*_source)->fail() && !line.empty()) {
|
||||
if (isspace(line[0])) {
|
||||
// If the line begins with a space, that continues the previous
|
||||
// field.
|
||||
@ -1122,7 +1077,7 @@ read_http_response() {
|
||||
}
|
||||
}
|
||||
|
||||
getline(*_source, line);
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
@ -1411,59 +1366,6 @@ parse_authentication_schemes(HTTPDocument::AuthenticationSchemes &schemes,
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::read_body
|
||||
// Access: Private
|
||||
// Description: Returns a newly-allocated istream suitable for
|
||||
// reading the body of the document. If owns_source is
|
||||
// true, the ownership of the _source pointer will be
|
||||
// passed to the istream; otherwise, it will be
|
||||
// retained. (owns_source must be true in order to read
|
||||
// "identity" encoded documents.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
istream *HTTPDocument::
|
||||
read_body(bool owns_source) {
|
||||
if (_state != S_read_header || _source == (IBioStream *)NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string transfer_coding = downcase(get_header_value("Transfer-Encoding"));
|
||||
string content_length = get_header_value("Content-Length");
|
||||
|
||||
istream *result;
|
||||
if (transfer_coding == "chunked") {
|
||||
// Chunked can be used directly.
|
||||
_file_size = 0;
|
||||
_state = S_started_body;
|
||||
_read_index++;
|
||||
result = new IChunkedStream(_source, owns_source, (HTTPDocument *)this);
|
||||
if (owns_source) {
|
||||
_source = (IBioStream *)NULL;
|
||||
}
|
||||
|
||||
} else if (!content_length.empty()) {
|
||||
// If we have a content length, we can use an IdentityStream.
|
||||
_state = S_started_body;
|
||||
_read_index++;
|
||||
result = new IIdentityStream(_source, owns_source, (HTTPDocument *)this, _file_size);
|
||||
if (owns_source) {
|
||||
_source = (IBioStream *)NULL;
|
||||
}
|
||||
|
||||
} else if (owns_source) {
|
||||
// If we own the source, we can return it.
|
||||
_state = S_started_body;
|
||||
result = _source;
|
||||
_source = (IBioStream *)NULL;
|
||||
|
||||
} else {
|
||||
// Otherwise, we don't own the source; too bad.
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: HTTPDocument::prepare_for_next
|
||||
// Access: Private
|
||||
@ -1473,15 +1375,21 @@ read_body(bool owns_source) {
|
||||
// skipping past the unread body in the persistent
|
||||
// connection, or it might do nothing at all if the body
|
||||
// has already been completely read.
|
||||
//
|
||||
// If allow_reconnect is true, then the current
|
||||
// connection may be automatically dropped and a new
|
||||
// connection reestablished if necessary; otherwise,
|
||||
// this function will fail (and return false) if
|
||||
// multiple connections are required.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool HTTPDocument::
|
||||
prepare_for_next() {
|
||||
prepare_for_next(bool allow_reconnect) {
|
||||
if (get_persistent_connection() && !will_close_connection() &&
|
||||
_proxy == _client->get_proxy()) {
|
||||
// See if we can reuse the current connection.
|
||||
if (_state == S_read_header) {
|
||||
// We have read the header; now skip past the body.
|
||||
istream *body = read_body(false);
|
||||
istream *body = read_body();
|
||||
if (body != (istream *)NULL) {
|
||||
string line;
|
||||
getline(*body, line);
|
||||
@ -1491,27 +1399,22 @@ prepare_for_next() {
|
||||
}
|
||||
getline(*body, line);
|
||||
}
|
||||
nassertr(body != _source, false);
|
||||
delete body;
|
||||
}
|
||||
}
|
||||
|
||||
if (_source == (IBioStream *)NULL) {
|
||||
_source = new IBioStream(_bio, false);
|
||||
}
|
||||
|
||||
if (_state == S_read_body) {
|
||||
// We have read the body, but there's a trailer to read.
|
||||
string line;
|
||||
getline(*_source, line);
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
if (downloader_cat.is_spam()) {
|
||||
downloader_cat.spam() << "skip: " << line << "\n";
|
||||
}
|
||||
while (!_source->eof() && !_source->fail() && !line.empty()) {
|
||||
getline(*_source, line);
|
||||
while (!(*_source)->eof() && !(*_source)->fail() && !line.empty()) {
|
||||
getline(**_source, line);
|
||||
if (!line.empty() && line[line.length() - 1] == '\r') {
|
||||
line = line.substr(0, line.length() - 1);
|
||||
}
|
||||
@ -1528,12 +1431,9 @@ prepare_for_next() {
|
||||
}
|
||||
}
|
||||
|
||||
if (_bio != (BIO *)NULL && _state == S_new) {
|
||||
if (!_bio.is_null() && _state == S_new) {
|
||||
// If we have a BIO and the _state is S_new, then we haven't done
|
||||
// anything with the BIO yet, so we can still use it.
|
||||
if (_source == (IBioStream *)NULL) {
|
||||
_source = new IBioStream(_bio, false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1541,9 +1441,9 @@ prepare_for_next() {
|
||||
// body, or we were only partly through reading the body elsewhere;
|
||||
// or possibly we don't have a connection yet at all. In any case,
|
||||
// we must now get a new connection.
|
||||
if (_bio != (BIO *)NULL && !_owns_bio) {
|
||||
// We have a connection, but we don't own it, so we can't close
|
||||
// it. Too bad.
|
||||
if (!_bio.is_null() && !allow_reconnect) {
|
||||
// We have a connection, and we're not allowed to throw it away.
|
||||
// Too bad.
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1553,9 +1453,7 @@ prepare_for_next() {
|
||||
_proxy = _client->get_proxy();
|
||||
_http_version = _client->get_http_version();
|
||||
_http_version_string = _client->get_http_version_string();
|
||||
_owns_bio = true;
|
||||
if (establish_connection()) {
|
||||
_source = new IBioStream(_bio, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1572,24 +1470,8 @@ prepare_for_next() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void HTTPDocument::
|
||||
free_bio() {
|
||||
if (_source != (IBioStream *)NULL) {
|
||||
delete _source;
|
||||
_source = (IBioStream *)NULL;
|
||||
}
|
||||
if (_bio != (BIO *)NULL) {
|
||||
if (_owns_bio) {
|
||||
// TODO: We should be more careful here to manage reference
|
||||
// counts so we don't free the bio out from under a BIOStreamBuf
|
||||
// that's trying to read from it.
|
||||
if (downloader_cat.is_debug()) {
|
||||
const URLSpec &url = _proxy.empty() ? _url : _proxy;
|
||||
downloader_cat.debug()
|
||||
<< "Dropping connection to " << url.get_server() << "\n";
|
||||
}
|
||||
BIO_free_all(_bio);
|
||||
}
|
||||
_bio = (BIO *)NULL;
|
||||
}
|
||||
_source.clear();
|
||||
_bio.clear();
|
||||
_read_index++;
|
||||
_state = S_new;
|
||||
}
|
||||
|
@ -31,10 +31,12 @@
|
||||
#include "httpClient.h"
|
||||
#include "urlSpec.h"
|
||||
#include "virtualFile.h"
|
||||
#include "bioPtr.h"
|
||||
#include "bioStreamPtr.h"
|
||||
#include "pmap.h"
|
||||
#include "pointerTo.h"
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
class IBioStream;
|
||||
class HTTPClient;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -43,11 +45,12 @@ class HTTPClient;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS HTTPDocument : public VirtualFile {
|
||||
private:
|
||||
HTTPDocument(HTTPClient *client, BIO *bio = NULL);
|
||||
HTTPDocument(HTTPClient *client);
|
||||
|
||||
bool send_request(const string &method, const URLSpec &url,
|
||||
const string &body);
|
||||
bool send_request(const string &header, const string &body);
|
||||
bool send_request(const string &header, const string &body,
|
||||
bool allow_reconnect);
|
||||
|
||||
public:
|
||||
virtual ~HTTPDocument();
|
||||
@ -78,9 +81,12 @@ PUBLISHED:
|
||||
|
||||
void write_headers(ostream &out) const;
|
||||
|
||||
INLINE bool get_document(const URLSpec &url, const string &body = string());
|
||||
INLINE bool post_form(const URLSpec &url, const string &body);
|
||||
INLINE bool get_document(const URLSpec &url);
|
||||
INLINE bool get_header(const URLSpec &url);
|
||||
|
||||
ISocketStream *read_body();
|
||||
|
||||
private:
|
||||
bool establish_connection();
|
||||
bool establish_http();
|
||||
@ -112,15 +118,13 @@ private:
|
||||
static void show_send(const string &message);
|
||||
#endif
|
||||
|
||||
istream *read_body(bool owns_source);
|
||||
bool prepare_for_next();
|
||||
bool prepare_for_next(bool allow_reconnect);
|
||||
void free_bio();
|
||||
|
||||
HTTPClient *_client;
|
||||
URLSpec _proxy;
|
||||
BIO *_bio;
|
||||
bool _owns_bio;
|
||||
IBioStream *_source;
|
||||
PT(BioPtr) _bio;
|
||||
PT(BioStreamPtr) _source;
|
||||
bool _persistent_connection;
|
||||
|
||||
URLSpec _url;
|
||||
|
@ -23,7 +23,7 @@
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IIdentityStream::
|
||||
IIdentityStream() : istream(&_buf) {
|
||||
IIdentityStream() : ISocketStream(&_buf) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -32,9 +32,11 @@ IIdentityStream() : istream(&_buf) {
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IIdentityStream::
|
||||
IIdentityStream(istream *source, bool owns_source,
|
||||
HTTPDocument *doc, size_t content_length) : istream(&_buf) {
|
||||
open(source, owns_source, doc, content_length);
|
||||
IIdentityStream(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length) :
|
||||
ISocketStream(&_buf)
|
||||
{
|
||||
open(source, doc, has_content_length, content_length);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -43,10 +45,10 @@ IIdentityStream(istream *source, bool owns_source,
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE IIdentityStream &IIdentityStream::
|
||||
open(istream *source, bool owns_source, HTTPDocument *doc,
|
||||
size_t content_length) {
|
||||
open(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length) {
|
||||
clear(0);
|
||||
_buf.open_read(source, owns_source, doc, content_length);
|
||||
_buf.open_read(source, doc, has_content_length, content_length);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -17,3 +17,25 @@
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "identityStream.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: IIdentityStream::is_closed
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns true if the last eof condition was triggered
|
||||
// because the socket has genuinely closed, or false if
|
||||
// we can expect more data to come along shortly.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool IIdentityStream::
|
||||
is_closed() {
|
||||
if ((_buf._has_content_length && _buf._bytes_remaining == 0) ||
|
||||
(*_buf._source)->is_closed()) {
|
||||
return true;
|
||||
}
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
@ -21,9 +21,14 @@
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "socketStream.h"
|
||||
#include "identityStreamBuf.h"
|
||||
|
||||
class HTTPDocument;
|
||||
class BioStreamPtr;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : IIdentityStream
|
||||
@ -39,22 +44,26 @@ class HTTPDocument;
|
||||
// completely read.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// No need to export from DLL.
|
||||
class IIdentityStream : public istream {
|
||||
class IIdentityStream : public ISocketStream {
|
||||
public:
|
||||
INLINE IIdentityStream();
|
||||
INLINE IIdentityStream(istream *source, bool owns_source,
|
||||
HTTPDocument *doc, size_t content_length);
|
||||
INLINE IIdentityStream(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length);
|
||||
|
||||
INLINE IIdentityStream &open(istream *source, bool owns_source,
|
||||
HTTPDocument *doc, size_t content_length);
|
||||
INLINE IIdentityStream &open(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length);
|
||||
INLINE IIdentityStream &close();
|
||||
|
||||
virtual bool is_closed();
|
||||
|
||||
private:
|
||||
IdentityStreamBuf _buf;
|
||||
};
|
||||
|
||||
#include "identityStream.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -18,6 +18,9 @@
|
||||
|
||||
#include "identityStreamBuf.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#ifndef HAVE_STREAMSIZE
|
||||
// Some compilers (notably SGI) don't define this for us
|
||||
typedef int streamsize;
|
||||
@ -30,8 +33,7 @@ typedef int streamsize;
|
||||
////////////////////////////////////////////////////////////////////
|
||||
IdentityStreamBuf::
|
||||
IdentityStreamBuf() {
|
||||
_source = (istream *)NULL;
|
||||
_owns_source = false;
|
||||
_has_content_length = true;
|
||||
_bytes_remaining = 0;
|
||||
|
||||
#ifdef WIN32_VC
|
||||
@ -68,11 +70,11 @@ IdentityStreamBuf::
|
||||
// from the identity encoding.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IdentityStreamBuf::
|
||||
open_read(istream *source, bool owns_source, HTTPDocument *doc,
|
||||
size_t content_length) {
|
||||
open_read(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length) {
|
||||
_source = source;
|
||||
_owns_source = owns_source;
|
||||
_doc = doc;
|
||||
_has_content_length = has_content_length;
|
||||
_bytes_remaining = content_length;
|
||||
|
||||
if (_doc != (HTTPDocument *)NULL) {
|
||||
@ -87,13 +89,7 @@ open_read(istream *source, bool owns_source, HTTPDocument *doc,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void IdentityStreamBuf::
|
||||
close_read() {
|
||||
if (_source != (istream *)NULL) {
|
||||
if (_owns_source) {
|
||||
delete _source;
|
||||
_owns_source = false;
|
||||
}
|
||||
_source = (istream *)NULL;
|
||||
}
|
||||
_source.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -137,24 +133,44 @@ underflow() {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
size_t IdentityStreamBuf::
|
||||
read_chars(char *start, size_t length) {
|
||||
if (_bytes_remaining == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (!_has_content_length) {
|
||||
// If we have no restrictions on content length, read till end of
|
||||
// file.
|
||||
(*_source)->read(start, length);
|
||||
length = (*_source)->gcount();
|
||||
|
||||
// Extract some of the bytes remaining in the chunk.
|
||||
length = min(length, _bytes_remaining);
|
||||
_source->read(start, length);
|
||||
length = _source->gcount();
|
||||
_bytes_remaining -= length;
|
||||
if (length == 0) {
|
||||
// End of file; we're done.
|
||||
if (_doc != (HTTPDocument *)NULL && _read_index == _doc->_read_index) {
|
||||
// An IdentityStreamBuf doesn't have a trailer, so we've already
|
||||
// "read" it.
|
||||
_doc->_state = HTTPDocument::S_read_trailer;
|
||||
}
|
||||
}
|
||||
|
||||
if (_bytes_remaining == 0) {
|
||||
// We're done.
|
||||
if (_doc != (HTTPDocument *)NULL && _read_index == _doc->_read_index) {
|
||||
// An IdentityStreamBuf doesn't have a trailer, so we've already
|
||||
// "read" it.
|
||||
_doc->_state = HTTPDocument::S_read_trailer;
|
||||
} else {
|
||||
if (_bytes_remaining == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Extract some of the bytes remaining in the chunk.
|
||||
|
||||
length = min(length, _bytes_remaining);
|
||||
(*_source)->read(start, length);
|
||||
length = (*_source)->gcount();
|
||||
_bytes_remaining -= length;
|
||||
|
||||
if (_bytes_remaining == 0) {
|
||||
// We're done.
|
||||
if (_doc != (HTTPDocument *)NULL && _read_index == _doc->_read_index) {
|
||||
// An IdentityStreamBuf doesn't have a trailer, so we've already
|
||||
// "read" it.
|
||||
_doc->_state = HTTPDocument::S_read_trailer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
@ -20,7 +20,12 @@
|
||||
#define IDENTITYSTREAMBUF_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// This module is not compiled if OpenSSL is not available.
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
#include "httpDocument.h"
|
||||
#include "bioStreamPtr.h"
|
||||
#include "pointerTo.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -33,8 +38,8 @@ public:
|
||||
IdentityStreamBuf();
|
||||
virtual ~IdentityStreamBuf();
|
||||
|
||||
void open_read(istream *source, bool owns_source, HTTPDocument *doc,
|
||||
size_t content_length);
|
||||
void open_read(BioStreamPtr *source, HTTPDocument *doc,
|
||||
bool has_content_length, size_t content_length);
|
||||
void close_read();
|
||||
|
||||
protected:
|
||||
@ -43,12 +48,16 @@ protected:
|
||||
private:
|
||||
size_t read_chars(char *start, size_t length);
|
||||
|
||||
istream *_source;
|
||||
bool _owns_source;
|
||||
PT(BioStreamPtr) _source;
|
||||
bool _has_content_length;
|
||||
size_t _bytes_remaining;
|
||||
|
||||
PT(HTTPDocument) _doc;
|
||||
int _read_index;
|
||||
|
||||
friend class IIdentityStream;
|
||||
};
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
#endif
|
||||
|
27
panda/src/downloader/socketStream.I
Normal file
27
panda/src/downloader/socketStream.I
Normal file
@ -0,0 +1,27 @@
|
||||
// Filename: socketStream.I
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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: ISocketStream::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE ISocketStream::
|
||||
ISocketStream(streambuf *buf) : istream(buf) {
|
||||
}
|
54
panda/src/downloader/socketStream.h
Normal file
54
panda/src/downloader/socketStream.h
Normal file
@ -0,0 +1,54 @@
|
||||
// Filename: socketStream.h
|
||||
// Created by: drose (15Oct02)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SOCKETSTREAM_H
|
||||
#define SOCKETSTREAM_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
// At the present, this module is not compiled if OpenSSL is not
|
||||
// available, since the only current use for it is to implement
|
||||
// OpenSSL-defined constructs (like ISocketStream).
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : ISocketStream
|
||||
// Description : This is a base class for istreams implemented in
|
||||
// Panda that read from a (possibly non-blocking)
|
||||
// socket. It adds is_closed(), which can be called
|
||||
// after an eof condition to check whether the socket
|
||||
// has been closed, or whether more data may be
|
||||
// available later.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDAEXPRESS ISocketStream : public istream {
|
||||
public:
|
||||
INLINE ISocketStream(streambuf *buf);
|
||||
|
||||
PUBLISHED:
|
||||
virtual bool is_closed() = 0;
|
||||
};
|
||||
|
||||
#include "socketStream.I"
|
||||
|
||||
#endif // HAVE_SSL
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user