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
URLSpec
A container for a URL, e.g.
Definition: urlSpec.h:28
virtualFileMountHTTP.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DocumentSpec::has_date
has_date
Returns true if a last-modified date is associated with the DocumentSpec.
Definition: documentSpec.h:82
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition: virtualFileSystem.h:40
Filename::get_fullpath
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
stringStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtualFileHTTP.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
StringStream
A bi-directional stream object that reads and writes data to an internal buffer, which can be retriev...
Definition: stringStream.h:27
DocumentSpec::get_date
get_date
Returns the last-modified date associated with the DocumentSpec, if there is one.
Definition: documentSpec.h:82
zStream.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DocumentSpec
A descriptor that refers to a particular version of a document.
Definition: documentSpec.h:30
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39