Panda3D
virtualFileHTTP.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file virtualFileHTTP.cxx
10  * @author drose
11  * @date 2008-10-31
12  */
13 
14 #include "virtualFileHTTP.h"
15 #include "virtualFileMountHTTP.h"
16 #include "stringStream.h"
17 #include "zStream.h"
18 
19 #ifdef HAVE_OPENSSL
20 
21 using std::istream;
22 using std::ostream;
23 using std::string;
24 
25 TypeHandle VirtualFileHTTP::_type_handle;
26 
27 
28 /**
29  *
30  */
31 VirtualFileHTTP::
32 VirtualFileHTTP(VirtualFileMountHTTP *mount, const Filename &local_filename,
33  bool implicit_pz_file, int open_flags) :
34  _mount(mount),
35  _local_filename(local_filename),
36  _implicit_pz_file(implicit_pz_file),
37  _status_only(open_flags != 0)
38 {
39  URLSpec url(_mount->get_root());
40  url.set_path(_mount->get_root().get_path() + _local_filename.c_str());
41  _channel = _mount->get_channel();
42  if (_status_only) {
43  _channel->get_header(url);
44  } else {
45  _channel->get_document(url);
46  }
47 }
48 
49 /**
50  *
51  */
52 VirtualFileHTTP::
53 ~VirtualFileHTTP() {
54  // Recycle the associated HTTPChannel, so we can use it again later without
55  // having to close the connection to the server.
56  _mount->recycle_channel(_channel);
57 }
58 
59 /**
60  * Returns the VirtualFileSystem this file is associated with.
61  */
62 VirtualFileSystem *VirtualFileHTTP::
63 get_file_system() const {
64  return _mount->get_file_system();
65 }
66 
67 /**
68  * Returns the full pathname to this file within the virtual file system.
69  */
70 Filename VirtualFileHTTP::
71 get_filename() const {
72  string mount_point = _mount->get_mount_point();
73  if (_local_filename.empty()) {
74  if (mount_point.empty()) {
75  return "/";
76  } else {
77  return string("/") + mount_point;
78  }
79 
80  } else {
81  if (mount_point.empty()) {
82  return string("/") + _local_filename.get_fullpath();
83  } else {
84  return string("/") + mount_point + string("/") + _local_filename.get_fullpath();
85  }
86  }
87 }
88 
89 /**
90  * Returns true if this file exists, false otherwise.
91  */
92 bool VirtualFileHTTP::
93 has_file() const {
94  return _channel->is_valid();
95 }
96 
97 /**
98  * Returns true if this file represents a directory (and scan_directory() may
99  * be called), false otherwise.
100  */
101 bool VirtualFileHTTP::
102 is_directory() const {
103  return false;
104 }
105 
106 /**
107  * Returns true if this file represents a regular file (and read_file() may be
108  * called), false otherwise.
109  */
110 bool VirtualFileHTTP::
111 is_regular_file() const {
112  return _channel->is_valid();
113 }
114 
115 /**
116  * Opens the file for reading. Returns a newly allocated istream on success
117  * (which you should eventually delete when you are done reading). Returns
118  * NULL on failure.
119  *
120  * If auto_unwrap is true, an explicitly-named .pz file is automatically
121  * decompressed and the decompressed contents are returned. This is different
122  * than vfs-implicit-pz, which will automatically decompress a file if the
123  * extension .pz is *not* given.
124  */
125 istream *VirtualFileHTTP::
126 open_read_file(bool auto_unwrap) const {
127  if (_status_only) {
128  return nullptr;
129  }
130 
131  // We pre-download the file into a StringStream, then return a buffer to
132  // that. It seems safer, since we can guarantee the file comes all at once
133  // without timeouts along the way.
134  StringStream *strstream = new StringStream;
135  if (!fetch_file(strstream)) {
136  delete strstream;
137  return nullptr;
138  }
139 
140  return return_file(strstream, auto_unwrap);
141 }
142 
143 /**
144  * Downloads the entire file from the web server into the indicated iostream.
145  * Returns true on success, false on failure.
146  *
147  * This seems to be safer than returning the socket stream directly, since
148  * this way we can better control timeouts and other internet hiccups. We can
149  * also offer seeking on the resulting stream.
150  */
151 bool VirtualFileHTTP::
152 fetch_file(ostream *buffer_stream) const {
153  _channel->download_to_stream(buffer_stream, false);
154  if (!_channel->is_download_complete()) {
155  // Failure to download fully. Try again to download more.
156 
157  URLSpec url(_mount->get_root());
158  url.set_path(_mount->get_root().get_path() + _local_filename.c_str());
159 
160  size_t bytes_downloaded = _channel->get_bytes_downloaded();
161  size_t last_byte = bytes_downloaded;
162 
163  while (bytes_downloaded > 0 && !_channel->is_download_complete()) {
164  _channel->get_subdocument(url, last_byte, 0);
165  _channel->download_to_stream(buffer_stream, true);
166  bytes_downloaded = _channel->get_bytes_downloaded();
167  last_byte = _channel->get_last_byte_delivered();
168  }
169  }
170 
171  return _channel->is_download_complete() && _channel->is_valid();
172 }
173 
174 /**
175  * After downloading the entire file via fetch_file(), rewinds the file stream
176  * and returns it as its own readable stream.
177  */
178 istream *VirtualFileHTTP::
179 return_file(istream *buffer_stream, bool auto_unwrap) const {
180  // Will we be automatically unwrapping a .pz file?
181  bool do_unwrap = (_implicit_pz_file || (auto_unwrap && _local_filename.get_extension() == "pz"));
182 
183  istream *result = buffer_stream;
184 #ifdef HAVE_ZLIB
185  if (result != nullptr && do_unwrap) {
186  // We have to slip in a layer to decompress the file on the fly.
187  IDecompressStream *wrapper = new IDecompressStream(result, true);
188  result = wrapper;
189  }
190 #endif // HAVE_ZLIB
191 
192  return result;
193 }
194 
195 /**
196  * Call this method after a reading the istream returned by open_read_file()
197  * to completion. If it returns true, the file was read completely and
198  * without error; if it returns false, there may have been some errors or a
199  * truncated file read. This is particularly likely if the stream is a
200  * VirtualFileHTTP.
201  */
202 bool VirtualFileHTTP::
203 was_read_successful() const {
204  return _channel->is_valid() && _channel->is_download_complete();
205 }
206 
207 /**
208  * Returns the current size on disk (or wherever it is) of the already-open
209  * file. Pass in the stream that was returned by open_read_file(); some
210  * implementations may require this stream to determine the size.
211  */
212 std::streamsize VirtualFileHTTP::
213 get_file_size(istream *stream) const {
214  return _channel->get_file_size();
215 }
216 
217 /**
218  * Returns the current size on disk (or wherever it is) of the file before it
219  * has been opened.
220  */
221 std::streamsize VirtualFileHTTP::
222 get_file_size() const {
223  return _channel->get_file_size();
224 }
225 
226 /**
227  * Returns a time_t value that represents the time the file was last modified,
228  * to within whatever precision the operating system records this information
229  * (on a Windows95 system, for instance, this may only be accurate to within 2
230  * seconds).
231  *
232  * If the timestamp cannot be determined, either because it is not supported
233  * by the operating system or because there is some error (such as file not
234  * found), returns 0.
235  */
236 time_t VirtualFileHTTP::
237 get_timestamp() const {
238  const DocumentSpec &spec = _channel->get_document_spec();
239  if (spec.has_date()) {
240  return spec.get_date().get_time();
241  }
242  return 0;
243 }
244 
245 #endif // HAVE_OPENSSL
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for a URL, e.g.
Definition: urlSpec.h:28
A hierarchy of directories and files that appears to be one continuous file system,...
get_date
Returns the last-modified date associated with the DocumentSpec, if there is one.
Definition: documentSpec.h:82
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
set_path
Replaces the path part of the URL specification.
Definition: urlSpec.h:99
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
has_date
Returns true if a last-modified date is associated with the DocumentSpec.
Definition: documentSpec.h:82
A descriptor that refers to a particular version of a document.
Definition: documentSpec.h:30
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A bi-directional stream object that reads and writes data to an internal buffer, which can be retriev...
Definition: stringStream.h:27