Browse Source

new http stuff

David Rose 23 years ago
parent
commit
ffd6bba8ad

+ 21 - 5
panda/src/downloader/Sources.pp

@@ -1,7 +1,7 @@
 #define LOCAL_LIBS event express pandabase
 #define OTHER_LIBS interrogatedb:c dconfig:c dtoolconfig:m \
                    dtoolutil:c dtoolbase:c dtool:m
-#define USE_PACKAGES zlib net
+#define USE_PACKAGES zlib net ssl
 
 #begin lib_target
   #define TARGET downloader
@@ -11,8 +11,14 @@
     $[if $[HAVE_ZLIB], $[TARGET]_composite4.cxx] \
 
   #define SOURCES \
-    config_downloader.h asyncUtility.I asyncUtility.h \
-    extractor.h  multiplexStream.I multiplexStream.h \
+    config_downloader.h \
+    asyncUtility.I asyncUtility.h \
+    bioStream.I bioStream.h bioStreamBuf.h \
+    chunkedStream.I chunkedStream.h chunkedStreamBuf.h \
+    extractor.h \
+    httpClient.I httpClient.h \
+    httpDocument.I httpDocument.h \
+    multiplexStream.I multiplexStream.h \
     multiplexStreamBuf.I multiplexStreamBuf.h \
     urlSpec.I urlSpec.h \
     $[if $[HAVE_NET], downloadDb.I downloadDb.h downloader.I downloader.h] \
@@ -20,19 +26,29 @@
     $[if $[HAVE_CRYPTO], patcher.cxx patcher.h patcher.I]
     
   #define INCLUDED_SOURCES                 \
-    config_downloader.cxx asyncUtility.cxx \
-    extractor.cxx multiplexStream.cxx multiplexStreamBuf.cxx \
+    config_downloader.cxx \
+    asyncUtility.cxx \
+    bioStream.cxx bioStreamBuf.cxx \
+    chunkedStream.cxx chunkedStreamBuf.cxx \
+    extractor.cxx \
+    httpClient.cxx \
+    httpDocument.cxx \
+    multiplexStream.cxx multiplexStreamBuf.cxx \
     urlSpec.cxx \
     $[if $[HAVE_NET], downloadDb.cxx downloader.cxx] \
     $[if $[HAVE_ZLIB], decompressor.cxx zcompressor.cxx download_utils.cxx]
 
   #define INSTALL_HEADERS \
     asyncUtility.h asyncUtility.I \
+    bioStream.I bioStream.h bioStreamBuf.h \
+    chunkedStream.I chunkedStream.h chunkedStreamBuf.h \
     config_downloader.h \
     decompressor.h \
     download_utils.h downloadDb.h downloadDb.I \
     downloader.h downloader.I \
     extractor.h \
+    httpClient.I httpClient.h \
+    httpDocument.I httpDocument.h \
     multiplexStream.I multiplexStream.h \
     multiplexStreamBuf.I multiplexStreamBuf.I \
     patcher.h patcher.I \

+ 61 - 0
panda/src/downloader/bioStream.I

@@ -0,0 +1,61 @@
+// Filename: bioStream.I
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IBioStream::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE IBioStream::
+IBioStream() : istream(&_buf) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IBioStream::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE IBioStream::
+IBioStream(BIO *source, bool owns_source) : istream(&_buf) {
+  open(source, owns_source);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IBioStream::open
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IBioStream &IBioStream::
+open(BIO *source, bool owns_source) {
+  clear(0);
+  _buf.open_read(source, owns_source);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IBioStream::close
+//       Access: Public
+//  Description: Resets the BioStream to empty, but does not actually
+//               close the source BIO unless owns_source was true.
+////////////////////////////////////////////////////////////////////
+INLINE IBioStream &IBioStream::
+close() {
+  _buf.close_read();
+  return *this;
+}

+ 19 - 0
panda/src/downloader/bioStream.cxx

@@ -0,0 +1,19 @@
+// Filename: bioStream.cxx
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bioStream.h"

+ 57 - 0
panda/src/downloader/bioStream.h

@@ -0,0 +1,57 @@
+// Filename: bioStream.h
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BIOSTREAM_H
+#define BIOSTREAM_H
+
+#include "pandabase.h"
+
+// This module is not compiled if OpenSSL is not available.
+#ifdef HAVE_SSL
+
+#include "bioStreamBuf.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : IBioStream
+// Description : An input stream object that reads data from an
+//               OpenSSL BIO object.  This is used by the HTTPClient
+//               and HTTPDocument classes to provide a C++ interface
+//               to OpenSSL.
+//
+//               Seeking is not supported.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS IBioStream : public istream {
+public:
+  INLINE IBioStream();
+  INLINE IBioStream(BIO *source, bool owns_source);
+
+  INLINE IBioStream &open(BIO *source, bool owns_source);
+  INLINE IBioStream &close();
+
+private:
+  BioStreamBuf _buf;
+};
+
+#include "bioStream.I"
+
+#endif  // HAVE_SSL
+
+
+#endif
+
+

+ 125 - 0
panda/src/downloader/bioStreamBuf.cxx

@@ -0,0 +1,125 @@
+// Filename: bioStreamBuf.cxx
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "bioStreamBuf.h"
+
+#ifdef HAVE_SSL
+
+#ifndef HAVE_STREAMSIZE
+// Some compilers (notably SGI) don't define this for us
+typedef int streamsize;
+#endif /* HAVE_STREAMSIZE */
+
+////////////////////////////////////////////////////////////////////
+//     Function: BioStreamBuf::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+BioStreamBuf::
+BioStreamBuf() {
+  _source = (BIO *)NULL;
+  _owns_source = false;
+
+#ifdef WIN32_VC
+  // In spite of the claims of the MSDN Library to the contrary,
+  // Windows doesn't seem to provide an allocate() function, so we'll
+  // do it by hand.
+  char *buf = new char[4096];
+  char *ebuf = buf + 4096;
+  setg(buf, ebuf, ebuf);
+  setp(buf, ebuf);
+
+#else
+  allocate();
+  setg(base(), ebuf(), ebuf());
+  setp(base(), ebuf());
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BioStreamBuf::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+BioStreamBuf::
+~BioStreamBuf() {
+  close_read();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BioStreamBuf::open_read
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BioStreamBuf::
+open_read(BIO *source, bool owns_source) {
+  _source = source;
+  _owns_source = owns_source;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BioStreamBuf::close_read
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void BioStreamBuf::
+close_read() {
+  if (_source != (BIO *)NULL) {
+    if (_owns_source) {
+      BIO_free_all(_source);
+      _owns_source = false;
+    }
+    _source = (BIO *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: BioStreamBuf::underflow
+//       Access: Protected, Virtual
+//  Description: Called by the system istream implementation when its
+//               internal buffer needs more characters.
+////////////////////////////////////////////////////////////////////
+int BioStreamBuf::
+underflow() {
+  // Sometimes underflow() is called even if the buffer is not empty.
+  if (gptr() >= egptr()) {
+    size_t buffer_size = egptr() - eback();
+    gbump(-(int)buffer_size);
+
+    size_t num_bytes = buffer_size;
+    size_t read_count = BIO_read(_source, gptr(), buffer_size);
+
+    if (read_count != num_bytes) {
+      // Oops, we didn't read what we thought we would.
+      if (read_count == 0) {
+        return EOF;
+      }
+
+      // Slide what we did read to the top of the buffer.
+      nassertr(read_count < num_bytes, EOF);
+      size_t delta = num_bytes - read_count;
+      memmove(gptr() + delta, gptr(), read_count);
+      gbump(delta);
+    }
+  }
+
+  return (unsigned char)*gptr();
+}
+
+
+#endif  // HAVE_SSL

+ 52 - 0
panda/src/downloader/bioStreamBuf.h

@@ -0,0 +1,52 @@
+// Filename: bioStreamBuf.h
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef BIOSTREAMBUF_H
+#define BIOSTREAMBUF_H
+
+#include "pandabase.h"
+
+// This module is not compiled if OpenSSL is not available.
+#ifdef HAVE_SSL
+
+#include <openssl/ssl.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : BioStreamBuf
+// Description : The streambuf object that implements
+//               IBioStream.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS BioStreamBuf : public streambuf {
+public:
+  BioStreamBuf();
+  virtual ~BioStreamBuf();
+
+  void open_read(BIO *source, bool owns_source);
+  void close_read();
+
+protected:
+  virtual int underflow(void);
+
+private:
+  BIO *_source;
+  bool _owns_source;
+};
+
+#endif  // HAVE_SSL
+
+#endif

+ 61 - 0
panda/src/downloader/chunkedStream.I

@@ -0,0 +1,61 @@
+// Filename: chunkedStream.I
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: IChunkedStream::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE IChunkedStream::
+IChunkedStream() : istream(&_buf) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IChunkedStream::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE IChunkedStream::
+IChunkedStream(istream *source, bool owns_source) : istream(&_buf) {
+  open(source, owns_source);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IChunkedStream::open
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE IChunkedStream &IChunkedStream::
+open(istream *source, bool owns_source) {
+  clear(0);
+  _buf.open_read(source, owns_source);
+  return *this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: IChunkedStream::close
+//       Access: Public
+//  Description: Resets the ChunkedStream to empty, but does not actually
+//               close the source CHUNKED unless owns_source was true.
+////////////////////////////////////////////////////////////////////
+INLINE IChunkedStream &IChunkedStream::
+close() {
+  _buf.close_read();
+  return *this;
+}

+ 19 - 0
panda/src/downloader/chunkedStream.cxx

@@ -0,0 +1,19 @@
+// Filename: chunkedStream.cxx
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "chunkedStream.h"

+ 50 - 0
panda/src/downloader/chunkedStream.h

@@ -0,0 +1,50 @@
+// Filename: chunkedStream.h
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CHUNKEDSTREAM_H
+#define CHUNKEDSTREAM_H
+
+#include "pandabase.h"
+
+#include "chunkedStreamBuf.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : IChunkedStream
+// Description : An input stream object that reads data from a source
+//               istream, but automatically decodes the "chunked"
+//               transfer-coding specified by an HTTP server.
+//
+//               Seeking is not supported.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS IChunkedStream : public istream {
+public:
+  INLINE IChunkedStream();
+  INLINE IChunkedStream(istream *source, bool owns_source);
+
+  INLINE IChunkedStream &open(istream *source, bool owns_source);
+  INLINE IChunkedStream &close();
+
+private:
+  ChunkedStreamBuf _buf;
+};
+
+#include "chunkedStream.I"
+
+#endif
+
+

+ 162 - 0
panda/src/downloader/chunkedStreamBuf.cxx

@@ -0,0 +1,162 @@
+// Filename: chunkedStreamBuf.cxx
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "chunkedStreamBuf.h"
+
+#ifndef HAVE_STREAMSIZE
+// Some compilers (notably SGI) don't define this for us
+typedef int streamsize;
+#endif /* HAVE_STREAMSIZE */
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+ChunkedStreamBuf::
+ChunkedStreamBuf() {
+  _source = (istream *)NULL;
+  _owns_source = false;
+  _chunk_remaining = 0;
+  _done = true;
+
+#ifdef WIN32_VC
+  // In spite of the claims of the MSDN Library to the contrary,
+  // Windows doesn't seem to provide an allocate() function, so we'll
+  // do it by hand.
+  char *buf = new char[4096];
+  char *ebuf = buf + 4096;
+  setg(buf, ebuf, ebuf);
+  setp(buf, ebuf);
+
+#else
+  allocate();
+  setg(base(), ebuf(), ebuf());
+  setp(base(), ebuf());
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::Destructor
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+ChunkedStreamBuf::
+~ChunkedStreamBuf() {
+  close_read();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::open_read
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void ChunkedStreamBuf::
+open_read(istream *source, bool owns_source) {
+  _source = source;
+  _owns_source = owns_source;
+  _chunk_remaining = 0;
+  _done = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::close_read
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+void ChunkedStreamBuf::
+close_read() {
+  if (_source != (istream *)NULL) {
+    if (_owns_source) {
+      delete _source;
+      _owns_source = false;
+    }
+    _source = (istream *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::underflow
+//       Access: Protected, Virtual
+//  Description: Called by the system istream implementation when its
+//               internal buffer needs more characters.
+////////////////////////////////////////////////////////////////////
+int ChunkedStreamBuf::
+underflow() {
+  // Sometimes underflow() is called even if the buffer is not empty.
+  if (gptr() >= egptr()) {
+    size_t buffer_size = egptr() - eback();
+    gbump(-(int)buffer_size);
+
+    size_t num_bytes = buffer_size;
+    size_t read_count = read_chars(gptr(), buffer_size);
+
+    if (read_count != num_bytes) {
+      // Oops, we didn't read what we thought we would.
+      if (read_count == 0) {
+        return EOF;
+      }
+
+      // Slide what we did read to the top of the buffer.
+      nassertr(read_count < num_bytes, EOF);
+      size_t delta = num_bytes - read_count;
+      memmove(gptr() + delta, gptr(), read_count);
+      gbump(delta);
+    }
+  }
+
+  return (unsigned char)*gptr();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ChunkedStreamBuf::read_chars
+//       Access: Private
+//  Description: Gets some characters from the source stream.
+////////////////////////////////////////////////////////////////////
+size_t ChunkedStreamBuf::
+read_chars(char *start, size_t length) {
+  if (_done) {
+    return 0;
+  }
+
+  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();
+    _chunk_remaining -= length;
+    return length;
+  }
+
+  // Read the next chunk.
+  string line;
+  getline(*_source, line);
+  if (!line.empty() && line[line.length() - 1] == '\r') {
+    line = line.substr(0, line.length() - 1);
+  }
+  int chunk_size = strtol(line.c_str(), NULL, 16);
+  if (chunk_size <= 0) {
+    // Last chunk; we're done.
+    _done = true;
+    return 0;
+  }
+
+  _chunk_remaining = (size_t)chunk_size;
+  return read_chars(start, length);
+}

+ 49 - 0
panda/src/downloader/chunkedStreamBuf.h

@@ -0,0 +1,49 @@
+// Filename: chunkedStreamBuf.h
+// Created by:  drose (25Sep02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CHUNKEDSTREAMBUF_H
+#define CHUNKEDSTREAMBUF_H
+
+#include "pandabase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ChunkedStreamBuf
+// Description : The streambuf object that implements
+//               IChunkedStream.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS ChunkedStreamBuf : public streambuf {
+public:
+  ChunkedStreamBuf();
+  virtual ~ChunkedStreamBuf();
+
+  void open_read(istream *source, bool owns_source);
+  void close_read();
+
+protected:
+  virtual int underflow(void);
+
+private:
+  size_t read_chars(char *start, size_t length);
+
+  istream *_source;
+  bool _owns_source;
+  size_t _chunk_remaining;
+  bool _done;
+};
+
+#endif

+ 4 - 2
panda/src/downloader/config_downloader.cxx

@@ -16,9 +16,10 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include <dconfig.h>
-#include <get_config_path.h>
+#include "dconfig.h"
+#include "get_config_path.h"
 #include "config_downloader.h"
+#include "httpDocument.h"
 
 
 Configure(config_downloader);
@@ -62,4 +63,5 @@ const int patcher_buffer_size =
         config_downloader.GetInt("patcher-buffer-size", 4096);
 
 ConfigureFn(config_downloader) {
+  HTTPDocument::init_type();
 }

+ 6 - 0
panda/src/downloader/downloader_composite1.cxx

@@ -1,6 +1,12 @@
 #include "config_downloader.cxx"
 #include "asyncUtility.cxx"
+#include "bioStream.cxx"
+#include "bioStreamBuf.cxx"
+#include "chunkedStream.cxx"
+#include "chunkedStreamBuf.cxx"
 #include "extractor.cxx"
+#include "httpClient.cxx"
+#include "httpDocument.cxx"
 #include "multiplexStream.cxx"
 #include "multiplexStreamBuf.cxx"
 #include "urlSpec.cxx"

+ 94 - 0
panda/src/downloader/httpClient.I

@@ -0,0 +1,94 @@
+// Filename: httpClient.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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE HTTPClient::
+HTTPClient() {
+  make_ctx();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::Copy Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE HTTPClient::
+HTTPClient(const HTTPClient &copy) : _proxy(copy._proxy) {
+  make_ctx();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPClient::
+operator = (const HTTPClient &copy) {
+  _proxy = copy._proxy;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE HTTPClient::
+~HTTPClient() {
+  SSL_CTX_free(_ssl_ctx);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::set_proxy
+//       Access: Published
+//  Description: Specifies the proxy URL to handle all http and
+//               https requests.
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPClient::
+set_proxy(const URLSpec &proxy) {
+  _proxy = proxy;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_proxy
+//       Access: Published
+//  Description: Returns the proxy URL to handle all http and
+//               https requests.
+////////////////////////////////////////////////////////////////////
+INLINE const URLSpec &HTTPClient::
+get_proxy() const {
+  return _proxy;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::make_ctx
+//       Access: Private
+//  Description: Creates the OpenSSL context object.
+////////////////////////////////////////////////////////////////////
+INLINE void HTTPClient::
+make_ctx() {
+  if (!_ssl_initialized) {
+    initialize_ssl();
+  }
+  _ssl_ctx = SSL_CTX_new(SSLv23_client_method());
+}

+ 269 - 0
panda/src/downloader/httpClient.cxx

@@ -0,0 +1,269 @@
+// Filename: httpClient.cxx
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "httpClient.h"
+#include "config_downloader.h"
+
+#ifndef NDEBUG
+#include <openssl/err.h>
+#endif
+
+bool HTTPClient::_ssl_initialized = false;
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_document
+//       Access: Published, Virtual
+//  Description: Opens the named document for reading, or if body is
+//               nonempty, posts data for 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::
+get_document(const URLSpec &url, const string &body) {
+  BIO *bio;
+
+  if (_proxy.empty()) {
+    if (url.get_scheme() == "https") {
+      bio = get_https(url, body);
+    } else {
+      bio = get_http(url, body);
+    }
+  } else {
+    if (url.get_scheme() == "https") {
+      bio = get_https_proxy(url, body);
+    } else {
+      bio = get_http_proxy(url, body);
+    }
+  }    
+
+  return new HTTPDocument(bio, true);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::initialize_ssl
+//       Access: Private, Static
+//  Description: Called once the first time this class is used to
+//               initialize the OpenSSL library.
+////////////////////////////////////////////////////////////////////
+void HTTPClient::
+initialize_ssl() {
+#ifndef NDEBUG
+  ERR_load_crypto_strings();
+  ERR_load_SSL_strings();
+#endif
+  OpenSSL_add_all_algorithms();
+
+  _ssl_initialized = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_https
+//       Access: Private
+//  Description: Opens the indicated URL directly as an ordinary http
+//               document.
+////////////////////////////////////////////////////////////////////
+BIO *HTTPClient::
+get_http(const URLSpec &url, const string &body) {
+  stringstream server;
+  server << url.get_server() << ":" << url.get_port();
+  string server_str = server.str();
+
+  BIO *bio = BIO_new_connect((char *)server_str.c_str());
+
+  if (BIO_do_connect(bio) <= 0) {
+    downloader_cat.info()
+      << "Could not contact server " << server << "\n";
+#ifndef NDEBUG
+    ERR_print_errors_fp(stderr);
+#endif
+    return NULL;
+  }
+
+  send_get_request(bio, url.get_path(), url.get_server(), body);
+  return bio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_https
+//       Access: Private
+//  Description: Opens the indicated URL directly as an https
+//               document.
+////////////////////////////////////////////////////////////////////
+BIO *HTTPClient::
+get_https(const URLSpec &url, const string &body) {
+  BIO *sbio = BIO_new_ssl_connect(_ssl_ctx);
+  SSL *ssl;
+  BIO_get_ssl(sbio, &ssl);
+  nassertr(ssl != (SSL *)NULL, NULL);
+  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
+  stringstream server;
+  server << url.get_server() << ":" << url.get_port();
+  string server_str = server.str();
+
+  BIO_set_conn_hostname(sbio, server_str.c_str());
+
+  if (BIO_do_connect(sbio) <= 0) {
+    downloader_cat.info()
+      << "Could not contact server " << server << "\n";
+#ifndef NDEBUG
+    ERR_print_errors_fp(stderr);
+#endif
+    return NULL;
+  }
+
+  if (BIO_do_handshake(sbio) <= 0) {
+    downloader_cat.info()
+      << "Could not establish SSL handshake with " << server << "\n";
+#ifndef NDEBUG
+    ERR_print_errors_fp(stderr);
+#endif
+    return NULL;
+  }
+
+  send_get_request(sbio, url.get_path(), url.get_server(), body);
+  return sbio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_http_proxy
+//       Access: Private
+//  Description: Opens the indicated URL via the proxy as an ordinary
+//               http document.
+////////////////////////////////////////////////////////////////////
+BIO *HTTPClient::
+get_http_proxy(const URLSpec &url, const string &body) {
+  stringstream proxy_server;
+  proxy_server << _proxy.get_server() << ":" << _proxy.get_port();
+  string proxy_server_str = proxy_server.str();
+
+  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 << "\n";
+#ifndef NDEBUG
+    ERR_print_errors_fp(stderr);
+#endif
+    return NULL;
+  }
+
+  send_get_request(bio, url, url.get_server(), body);
+  return bio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::get_https_proxy
+//       Access: Private
+//  Description: Opens the indicated URL via the proxy as an https
+//               document.
+////////////////////////////////////////////////////////////////////
+BIO *HTTPClient::
+get_https_proxy(const URLSpec &url, const string &body) {
+  // First, ask the proxy to open a connection for us.
+  stringstream proxy_server;
+  proxy_server << _proxy.get_server() << ":" << _proxy.get_port();
+  string proxy_server_str = proxy_server.str();
+
+  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 << "\n";
+#ifndef NDEBUG
+    ERR_print_errors_fp(stderr);
+#endif
+    return NULL;
+  }
+
+  {
+    ostringstream request;
+    request 
+      << "CONNECT " << url.get_authority() << " HTTP/1.1\r\n"
+      << "\r\n";
+    string request_str = request.str();
+    
+    BIO_puts(bio, request_str.c_str());
+  }
+
+  // Create a temporary HTTPDocument to read the response from the
+  // proxy.
+  {
+    PT(HTTPDocument) doc = new HTTPDocument(bio, false);
+    if (!doc->is_valid()) {
+      downloader_cat.info()
+        << "proxy would not open connection to " << url.get_authority()
+        << ": " << doc->get_status_code() << " "
+        << doc->get_status_string() << "\n";
+      
+      // If the proxy won't open a raw connection for us, see if it will
+      // handle the https communication directly.
+      BIO_free_all(bio);
+      return get_http_proxy(url, body);
+    }
+  }
+
+  // Ok, we now have a connection to our actual server, so start
+  // speaking SSL and then ask for the document we really want.
+
+  BIO *sbio = BIO_new_ssl(_ssl_ctx, true);
+  BIO_push(sbio, bio);
+
+  SSL *ssl;
+  BIO_get_ssl(sbio, &ssl);
+  nassertr(ssl != (SSL *)NULL, NULL);
+  SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+
+  send_get_request(sbio, url.get_path(), url.get_server(), body);
+  return sbio;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPClient::send_get_request
+//       Access: Private
+//  Description: Sends the appropriate GET or POST request to the
+//               server on the indicated connection.
+////////////////////////////////////////////////////////////////////
+void HTTPClient::
+send_get_request(BIO *bio, 
+                 const string &path, const string &server, 
+                 const string &body) const {
+  ostringstream request;
+
+  if (body.empty()) {
+    request 
+      << "GET " << path << " HTTP/1.1\r\n"
+      << "Host: " << server << "\r\n"
+      << "Connection: close\r\n"
+      << "\r\n";
+  } else {
+    request 
+      << "POST " << path << " HTTP/1.1\r\n"
+      << "Host: " << server << "\r\n"
+      << "Connection: close\r\n"
+      << "Content-type: application/x-www-form-urlencoded\r\n"
+      << "Content-Length: " << body.length() << "\r\n"
+      << "\r\n"
+      << body;
+  }
+
+  string request_str = request.str();
+  BIO_puts(bio, request_str.c_str());
+}

+ 78 - 0
panda/src/downloader/httpClient.h

@@ -0,0 +1,78 @@
+// Filename: httpClient.h
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef HTTPCLIENT_H
+#define HTTPCLIENT_H
+
+#include "pandabase.h"
+
+// This module requires OpenSSL to compile, even if you do not intend
+// to use this to establish https connections; this is because it uses
+// the OpenSSL library to portably handle all of the socket
+// communications.
+
+#ifdef HAVE_SSL
+
+#include "urlSpec.h"
+#include "httpDocument.h"
+#include "pointerTo.h"
+
+#include <openssl/ssl.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : HTTPClient
+// Description : Handles contacting an HTTP server and retrieving a
+//               document.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS HTTPClient {
+PUBLISHED:
+  INLINE HTTPClient();
+  INLINE HTTPClient(const HTTPClient &copy);
+  INLINE void operator = (const HTTPClient &copy);
+  INLINE ~HTTPClient();
+
+  INLINE void set_proxy(const URLSpec &proxy);
+  INLINE const URLSpec &get_proxy() const;
+
+  PT(HTTPDocument) get_document(const URLSpec &url, const string &body = string());
+
+private:
+  INLINE void make_ctx();
+  static void initialize_ssl();
+
+  BIO *get_http(const URLSpec &url, const string &body);
+  BIO *get_https(const URLSpec &url, const string &body);
+  BIO *get_http_proxy(const URLSpec &url, const string &body);
+  BIO *get_https_proxy(const URLSpec &url, const string &body);
+
+  void send_get_request(BIO *bio, 
+                        const string &path, const string &server, 
+                        const string &body) const;
+
+  URLSpec _proxy;
+  SSL_CTX *_ssl_ctx;
+
+  static bool _ssl_initialized;
+};
+
+#include "httpClient.I"
+
+#endif  // HAVE_SSL
+
+#endif
+  

+ 66 - 0
panda/src/downloader/httpDocument.I

@@ -0,0 +1,66 @@
+// Filename: httpDocument.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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::is_valid
+//       Access: Published
+//  Description: Returns true if the document was successfully
+//               retrieved and is ready to be read, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool HTTPDocument::
+is_valid() const {
+  return (_source != (IBioStream *)NULL && 
+          (_status_code / 100) == 2);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::get_http_version
+//       Access: Published
+//  Description: Returns the HTTP version number returned by the
+//               server, formatted as a string, e.g. "HTTP/1.1".
+////////////////////////////////////////////////////////////////////
+INLINE const string &HTTPDocument::
+get_http_version() const {
+  return _http_version;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::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 HTTPDocument::
+get_status_code() const {
+  return _status_code;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::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 &HTTPDocument::
+get_status_string() const {
+  return _status_string;
+}

+ 246 - 0
panda/src/downloader/httpDocument.cxx

@@ -0,0 +1,246 @@
+// Filename: httpDocument.cxx
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "httpDocument.h"
+#include "bioStream.h"
+#include "chunkedStream.h"
+
+TypeHandle HTTPDocument::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+HTTPDocument::
+HTTPDocument(BIO *bio, bool owns_bio) {
+  if (bio != (BIO *)NULL) {
+    _source = new IBioStream(bio, owns_bio);
+    read_headers();
+
+  } else {
+    _source = (IBioStream *)NULL;
+    _status_code = 0;
+    _status_string = "No connection";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+HTTPDocument::
+~HTTPDocument() {
+  if (_source != (IBioStream *)NULL) {
+    delete _source;
+    _source = (IBioStream *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::get_file_system
+//       Access: Published, Virtual
+//  Description: Returns the VirtualFileSystem this file is associated
+//               with.
+////////////////////////////////////////////////////////////////////
+VirtualFileSystem *HTTPDocument::
+get_file_system() const {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::get_filename
+//       Access: Published, Virtual
+//  Description: Returns the full pathname to this file within the
+//               virtual file system.
+////////////////////////////////////////////////////////////////////
+Filename HTTPDocument::
+get_filename() const {
+  return Filename();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::is_regular_file
+//       Access: Published, Virtual
+//  Description: Returns true if this file represents a regular file
+//               (and read_file() may be called), false otherwise.
+////////////////////////////////////////////////////////////////////
+bool HTTPDocument::
+is_regular_file() const {
+  return is_valid();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::open_read_file
+//       Access: Public, Virtual
+//  Description: Opens the document for reading.  Returns a newly
+//               allocated istream on success (which you should
+//               eventually delete when you are done reading).
+//               Returns NULL on failure.
+////////////////////////////////////////////////////////////////////
+istream *HTTPDocument::
+open_read_file() const {
+  if (_source == (IBioStream *)NULL) {
+    return NULL;
+  }
+
+  string transfer_coding = get_header_value("Transfer-Encoding");
+  for (string::iterator si = transfer_coding.begin();
+       si != transfer_coding.end();
+       ++si) {
+    (*si) = tolower(*si);
+  }
+
+  if (transfer_coding == "chunked") {
+    return new IChunkedStream(_source, false);
+
+  } else {
+    istream *result = _source;
+    ((HTTPDocument *)this)->_source = (IBioStream *)NULL;
+    return result;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::get_header_value
+//       Access: Published
+//  Description: Returns the HTML header value associated with the
+//               indicated key, or empty string if the key was not
+//               defined in the message returned by the server.
+////////////////////////////////////////////////////////////////////
+string HTTPDocument::
+get_header_value(const string &key) const {
+  Headers::const_iterator hi = _headers.find(key);
+  if (hi != _headers.end()) {
+    return (*hi).second;
+  }
+  return string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::write_headers
+//       Access: Published
+//  Description: Outputs a list of all headers defined by the server
+//               to the indicated output stream.
+////////////////////////////////////////////////////////////////////
+void HTTPDocument::
+write_headers(ostream &out) const {
+  Headers::const_iterator hi;
+  for (hi = _headers.begin(); hi != _headers.end(); ++hi) {
+    out << (*hi).first << ": " << (*hi).second << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: HTTPDocument::read_headers
+//       Access: Private
+//  Description: Reads all of the responses from the server up until
+//               the first blank line, and stores the list of header
+//               key:value pairs so retrieved.
+////////////////////////////////////////////////////////////////////
+void HTTPDocument::
+read_headers() {
+  nassertv(_source != (IBioStream *)NULL);
+
+  // The first line back should include the HTTP version and the
+  // result code.
+  string line;
+  getline(*_source, line);
+  if (!line.empty() && line[line.length() - 1] == '\r') {
+    line = line.substr(0, line.length() - 1);
+  }
+  if (!(*_source) || line.length() < 5 || line.substr(0, 5) != "HTTP/") {
+    // Not an HTTP response.
+    _status_code = 0;
+    _status_string = "Not an HTTP response";
+    return;
+  }
+
+  // Split out the first line into its three components.
+  size_t p = 5;
+  while (p < line.length() && !isspace(line[p])) {
+    p++;
+  }
+  _http_version = line.substr(0, p);
+
+  while (p < line.length() && isspace(line[p])) {
+    p++;
+  }
+  size_t q = p;
+  while (q < line.length() && !isspace(line[q])) {
+    q++;
+  }
+  string status_code = line.substr(p, q - p);
+  _status_code = atoi(status_code.c_str());
+
+  while (q < line.length() && isspace(line[q])) {
+    q++;
+  }
+  _status_string = line.substr(q, line.length() - q);
+
+  // Now read the rest of the lines.  These will be field: value
+  // pairs.
+  string field_name;
+  string field_value;
+
+  getline(*_source, line);
+  if (!line.empty() && line[line.length() - 1] == '\r') {
+    line = line.substr(0, line.length() - 1);
+  }
+  while (!_source->eof() && !_source->fail() && !line.empty()) {
+    if (isspace(line[0])) {
+      // If the line begins with a space, that continues the previous
+      // field.
+      p = 0;
+      while (p < line.length() && isspace(line[p])) {
+        p++;
+      }
+      field_value += line.substr(p - 1);
+
+    } else {
+      // If the line does not begin with a space, that defines a new
+      // field.
+      if (!field_name.empty()) {
+        _headers[field_name] = field_value;
+        field_value = string();
+      }
+
+      size_t colon = line.find(':');
+      if (colon != string::npos) {
+        field_name = line.substr(0, colon);
+        p = colon + 1;
+        while (p < line.length() && isspace(line[p])) {
+          p++;
+        }
+        field_value = line.substr(p);
+      }
+    }
+
+    getline(*_source, line);
+    if (!line.empty() && line[line.length() - 1] == '\r') {
+      line = line.substr(0, line.length() - 1);
+    }
+  }
+  if (!field_name.empty()) {
+    _headers[field_name] = field_value;
+    field_value = string();
+  }
+
+  // A blank line terminates the headers.
+}

+ 99 - 0
panda/src/downloader/httpDocument.h

@@ -0,0 +1,99 @@
+// Filename: httpDocument.h
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef HTTPDOCUMENT_H
+#define HTTPDOCUMENT_H
+
+#include "pandabase.h"
+
+// This module requires OpenSSL to compile, even if you do not intend
+// to use this to establish https connections; this is because it uses
+// the OpenSSL library to portably handle all of the socket
+// communications.
+
+#ifdef HAVE_SSL
+
+#include "urlSpec.h"
+#include "virtualFile.h"
+#include "pmap.h"
+#include <openssl/ssl.h>
+
+class IBioStream;
+
+////////////////////////////////////////////////////////////////////
+//       Class : HTTPDocument
+// Description : A single document retrieved from an HTTP server.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDAEXPRESS HTTPDocument : public VirtualFile {
+public:
+  HTTPDocument(BIO *bio, bool owns_bio);
+  virtual ~HTTPDocument();
+
+  virtual VirtualFileSystem *get_file_system() const;
+  virtual Filename get_filename() const;
+
+  virtual bool is_regular_file() const;
+  virtual istream *open_read_file() const;
+
+PUBLISHED:
+  INLINE bool is_valid() const;
+  INLINE const string &get_http_version() const;
+  INLINE int get_status_code() const;
+  INLINE const string &get_status_string() const;
+  string get_header_value(const string &key) const;
+
+  void write_headers(ostream &out) const;
+
+private:
+  void read_headers();
+
+  IBioStream *_source;
+
+  string _http_version;
+  int _status_code;
+  string _status_string;
+
+  typedef pmap<string, string> Headers;
+  Headers _headers;
+
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    VirtualFile::init_type();
+    register_type(_type_handle, "HTTPDocument",
+                  VirtualFile::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "httpDocument.I"
+
+#endif  // HAVE_SSL
+
+#endif
+
+

+ 52 - 0
panda/src/downloader/urlSpec.I

@@ -195,6 +195,58 @@ get_url() const {
   return _url;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: URLSpec::string typecast operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE URLSpec::
+operator const string & () const {
+  return _url;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: URLSpec::c_str
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE const char *URLSpec::
+c_str() const {
+  return _url.c_str();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: URLSpec::empty
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool URLSpec::
+empty() const {
+  return _url.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: URLSpec::length
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE size_t URLSpec::
+length() const {
+  return _url.length();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: URLSpec::Indexing operator
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE char URLSpec::
+operator [] (int n) const {
+  nassertr(n >= 0 && n < (int)_url.length(), '\0');
+  return _url[n];
+}
+
+
 INLINE ostream &
 operator << (ostream &out, const URLSpec &url) {
   url.output(out);

+ 26 - 25
panda/src/downloader/urlSpec.cxx

@@ -471,7 +471,7 @@ output(ostream &out) const {
 string URLSpec::
 quote(const string &source, const string &safe) {
   ostringstream result;
-  result << hex << setw(2) << setfill('0');
+  result << hex << setfill('0');
 
   for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
     char ch = (*si);
@@ -495,7 +495,7 @@ quote(const string &source, const string &safe) {
 
       } else {
         // Otherwise, escape it.
-        result << "0x" << ch;
+        result << '%' << setw(2) << (int)ch;
       }
     }
   }
@@ -512,7 +512,7 @@ quote(const string &source, const string &safe) {
 string URLSpec::
 quote_plus(const string &source, const string &safe) {
   ostringstream result;
-  result << hex << setw(2) << setfill('0');
+  result << hex << setfill('0');
 
   for (string::const_iterator si = source.begin(); si != source.end(); ++si) {
     char ch = (*si);
@@ -540,7 +540,7 @@ quote_plus(const string &source, const string &safe) {
 
       } else {
         // Otherwise, escape it.
-        result << "0x" << ch;
+        result << '%' << setw(2) << (int)ch;
       }
     }
   }
@@ -559,27 +559,27 @@ string URLSpec::
 unquote(const string &source) {
   string result;
 
-  string::const_iterator si = source.begin();
-  while (si != source.end()) {
-    if ((*si) == '%') {
-      ++si;
+  size_t p = 0;
+  while (p < source.length()) {
+    if (source[p] == '%' && p + 2 < source.length()) {
       int hex = 0;
-      while (si != source.end() && isxdigit(*si)) {
+      p++;
+      for (int i = 0; i < 2; i++) {
         int value;
-        char ch = *si;
+        char ch = source[p + i];
         if (isdigit(ch)) {
           value = ch - '0';
         } else {
           value = tolower(ch) - 'a';
         }
-        hex = (hex << 8) | value;
-        ++si;
+        hex = (hex << 4) | value;
       }
       result += (char)hex;
+      p += 2;
 
     } else {
-      result += (*si);
-      ++si;
+      result += source[p];
+      p++;
     }
   }
 
@@ -597,30 +597,31 @@ string URLSpec::
 unquote_plus(const string &source) {
   string result;
 
-  string::const_iterator si = source.begin();
-  while (si != source.end()) {
-    if ((*si) == '%') {
-      ++si;
+  size_t p = 0;
+  while (p < source.length()) {
+    if (source[p] == '%' && p + 2 < source.length()) {
       int hex = 0;
-      while (si != source.end() && isxdigit(*si)) {
+      p++;
+      for (int i = 0; i < 2; i++) {
         int value;
-        char ch = *si;
+        char ch = source[p + i];
         if (isdigit(ch)) {
           value = ch - '0';
         } else {
           value = tolower(ch) - 'a';
         }
-        hex = (hex << 8) | value;
-        ++si;
+        hex = (hex << 4) | value;
       }
       result += (char)hex;
+      p += 2;
 
-    } else if ((*si) == '+') {
+    } else if (source[p] == '+') {
       result += ' ';
+      p++;
 
     } else {
-      result += (*si);
-      ++si;
+      result += source[p];
+      p++;
     }
   }
 

+ 7 - 0
panda/src/downloader/urlSpec.h

@@ -20,6 +20,7 @@
 #define URLSPEC_H
 
 #include "pandabase.h"
+#include "notify.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : URLSpec
@@ -67,6 +68,12 @@ PUBLISHED:
 
   void set_url(const string &url);
 
+  INLINE operator const string & () const;
+  INLINE const char *c_str() const;
+  INLINE bool empty() const;
+  INLINE size_t length() const;
+  INLINE char operator [] (int n) const;
+
   void output(ostream &out) const;
 
   static string quote(const string &source, const string &safe = "/");