Panda3D
httpChannel.h
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 httpChannel.h
10  * @author drose
11  * @date 2002-09-24
12  */
13 
14 #ifndef HTTPCHANNEL_H
15 #define HTTPCHANNEL_H
16 
17 #include "pandabase.h"
18 
19 // This module requires OpenSSL to compile, even if you do not intend to use
20 // this to establish https connections; this is because it uses the OpenSSL
21 // library to portably handle all of the socket communications.
22 
23 #ifdef HAVE_OPENSSL
24 
25 #include "httpClient.h"
26 #include "httpEnum.h"
27 #include "urlSpec.h"
28 #include "documentSpec.h"
29 #include "bioPtr.h"
30 #include "bioStreamPtr.h"
31 #include "pmap.h"
32 #include "pvector.h"
33 #include "pointerTo.h"
34 #include "config_downloader.h"
35 #include "filename.h"
36 #include "typedReferenceCount.h"
37 
38 typedef struct bio_st BIO;
39 
40 class Ramfile;
41 class HTTPClient;
42 
43 /**
44  * A single channel of communication from an HTTPClient. This is similar to
45  * the concept of a 'connection', except that HTTP is technically
46  * connectionless; in fact, a channel may represent one unbroken connection or
47  * it may transparently close and reopen a new connection with each request.
48  *
49  * A channel is conceptually a single thread of I/O. One document at a time
50  * may be requested using a channel; a new document may (in general) not be
51  * requested from the same HTTPChannel until the first document has been fully
52  * retrieved.
53  */
54 class EXPCL_PANDA_DOWNLOADER HTTPChannel : public TypedReferenceCount {
55 private:
56  HTTPChannel(HTTPClient *client);
57 
58 public:
59  virtual ~HTTPChannel();
60 
61 PUBLISHED:
62  // get_status_code() will either return an HTTP-style status code >= 100
63  // (e.g. 404), or one of the following values. In general, these are
64  // ordered from less-successful to more-successful.
65  enum StatusCode {
66  SC_incomplete = 0,
67  SC_internal_error,
68  SC_no_connection,
69  SC_timeout,
70  SC_lost_connection,
71  SC_non_http_response,
72  SC_invalid_http,
73  SC_socks_invalid_version,
74  SC_socks_no_acceptable_login_method,
75  SC_socks_refused,
76  SC_socks_no_connection,
77  SC_ssl_internal_failure,
78  SC_ssl_no_handshake,
79 
80  // No one returns this code, but StatusCode values higher than this are
81  // deemed more successful than any generic HTTP response.
82  SC_http_error_watermark,
83 
84  SC_ssl_invalid_server_certificate,
85  SC_ssl_self_signed_server_certificate,
86  SC_ssl_unexpected_server,
87 
88  // These errors are only generated after a download_to_*() call been
89  // issued.
90  SC_download_open_error,
91  SC_download_write_error,
92  SC_download_invalid_range,
93  };
94 
95  INLINE HTTPClient *get_client() const;
96 
97  INLINE bool is_valid() const;
98  INLINE bool is_connection_ready() const;
99 
100  INLINE const URLSpec &get_url() const;
101  INLINE const DocumentSpec &get_document_spec() const;
102  INLINE HTTPEnum::HTTPVersion get_http_version() const;
103  INLINE const std::string &get_http_version_string() const;
104  INLINE int get_status_code() const;
105  std::string get_status_string() const;
106  INLINE const std::string &get_www_realm() const;
107  INLINE const std::string &get_proxy_realm() const;
108  INLINE const URLSpec &get_redirect() const;
109  std::string get_header_value(const std::string &key) const;
110 
111  INLINE int get_num_redirect_steps() const;
112  INLINE const URLSpec &get_redirect_step(int n) const;
113  MAKE_SEQ(get_redirect_steps, get_num_redirect_steps, get_redirect_step);
114 
115  INLINE void set_persistent_connection(bool persistent_connection);
116  INLINE bool get_persistent_connection() const;
117  bool will_close_connection() const;
118 
119  INLINE void set_allow_proxy(bool allow_proxy);
120  INLINE bool get_allow_proxy() const;
121  INLINE void set_proxy_tunnel(bool proxy_tunnel);
122  INLINE bool get_proxy_tunnel() const;
123 
124  INLINE void set_connect_timeout(double timeout_seconds);
125  INLINE double get_connect_timeout() const;
126  INLINE void set_blocking_connect(bool blocking_connect);
127  INLINE bool get_blocking_connect() const;
128 
129  INLINE void set_http_timeout(double timeout_seconds);
130  INLINE double get_http_timeout() const;
131 
132  INLINE void set_skip_body_size(size_t skip_body_size);
133  INLINE size_t get_skip_body_size() const;
134  INLINE void set_idle_timeout(double idle_timeout);
135  INLINE double get_idle_timeout() const;
136 
137  INLINE void set_download_throttle(bool download_throttle);
138  INLINE bool get_download_throttle() const;
139 
140  INLINE void set_max_bytes_per_second(double max_bytes_per_second);
141  INLINE double get_max_bytes_per_second() const;
142 
143  INLINE void set_max_updates_per_second(double max_updates_per_second);
144  INLINE double get_max_updates_per_second() const;
145 
146  INLINE void set_content_type(std::string content_type);
147  INLINE std::string get_content_type() const;
148 
149  INLINE void set_expected_file_size(size_t file_size);
150  std::streamsize get_file_size() const;
151  INLINE bool is_file_size_known() const;
152 
153  INLINE size_t get_first_byte_requested() const;
154  INLINE size_t get_last_byte_requested() const;
155  INLINE size_t get_first_byte_delivered() const;
156  INLINE size_t get_last_byte_delivered() const;
157 
158  void write_headers(std::ostream &out) const;
159 
160  INLINE void reset();
161  INLINE void preserve_status();
162 
163  INLINE void clear_extra_headers();
164  INLINE void send_extra_header(const std::string &key, const std::string &value);
165 
166  BLOCKING INLINE bool get_document(const DocumentSpec &url);
167  BLOCKING INLINE bool get_subdocument(const DocumentSpec &url,
168  size_t first_byte, size_t last_byte);
169  BLOCKING INLINE bool get_header(const DocumentSpec &url);
170  BLOCKING INLINE bool post_form(const DocumentSpec &url, const std::string &body);
171  BLOCKING INLINE bool put_document(const DocumentSpec &url, const std::string &body);
172  BLOCKING INLINE bool delete_document(const DocumentSpec &url);
173  BLOCKING INLINE bool get_trace(const DocumentSpec &url);
174  BLOCKING INLINE bool connect_to(const DocumentSpec &url);
175  BLOCKING INLINE bool get_options(const DocumentSpec &url);
176 
177  INLINE void begin_get_document(const DocumentSpec &url);
178  INLINE void begin_get_subdocument(const DocumentSpec &url,
179  size_t first_byte, size_t last_byte);
180  INLINE void begin_get_header(const DocumentSpec &url);
181  INLINE void begin_post_form(const DocumentSpec &url, const std::string &body);
182  bool run();
183  INLINE void begin_connect_to(const DocumentSpec &url);
184 
185  ISocketStream *open_read_body();
186  void close_read_body(std::istream *stream) const;
187 
188  BLOCKING bool download_to_file(const Filename &filename, bool subdocument_resumes = true);
189  BLOCKING bool download_to_ram(Ramfile *ramfile, bool subdocument_resumes = true);
190  BLOCKING bool download_to_stream(std::ostream *strm, bool subdocument_resumes = true);
191  SocketStream *get_connection();
192 
193  INLINE size_t get_bytes_downloaded() const;
194  INLINE size_t get_bytes_requested() const;
195  INLINE bool is_download_complete() const;
196 
197 public:
198  static std::string downcase(const std::string &s);
199  void body_stream_destructs(ISocketStream *stream);
200 
201 private:
202  bool reached_done_state();
203  bool run_try_next_proxy();
204  bool run_connecting();
205  bool run_connecting_wait();
206  bool run_http_proxy_ready();
207  bool run_http_proxy_request_sent();
208  bool run_http_proxy_reading_header();
209  bool run_socks_proxy_greet();
210  bool run_socks_proxy_greet_reply();
211  bool run_socks_proxy_connect();
212  bool run_socks_proxy_connect_reply();
213  bool run_setup_ssl();
214  bool run_ssl_handshake();
215  bool run_ready();
216  bool run_request_sent();
217  bool run_reading_header();
218  bool run_start_direct_file_read();
219  bool run_read_header();
220  bool run_begin_body();
221  bool run_reading_body();
222  bool run_read_body();
223  bool run_read_trailer();
224 
225  bool run_download_to_file();
226  bool run_download_to_ram();
227  bool run_download_to_stream();
228 
229  void begin_request(HTTPEnum::Method method, const DocumentSpec &url,
230  const std::string &body, bool nonblocking,
231  size_t first_byte, size_t last_byte);
232  void reconsider_proxy();
233  void reset_for_new_request();
234 
235  void finished_body(bool has_trailer);
236  bool open_download_file();
237 
238  bool server_getline(std::string &str);
239  bool server_getline_failsafe(std::string &str);
240  bool server_get(std::string &str, size_t num_bytes);
241  bool server_get_failsafe(std::string &str, size_t num_bytes);
242  bool server_send(const std::string &str, bool secret);
243  bool parse_http_response(const std::string &line);
244  bool parse_http_header();
245  bool parse_content_range(const std::string &content_range);
246 
247  void check_socket();
248 
249  void check_preapproved_server_certificate(X509 *cert, bool &cert_preapproved,
250  bool &cert_name_preapproved) const;
251  bool validate_server_name(X509 *cert);
252  static bool match_cert_name(const std::string &cert_name, const std::string &hostname);
253  static std::string get_x509_name_component(X509_NAME *name, int nid);
254 
255  void make_header();
256  void make_proxy_request_text();
257  void make_request_text();
258 
259  void reset_url(const URLSpec &old_url, const URLSpec &new_url);
260  void store_header_field(const std::string &field_name, const std::string &field_value);
261 
262 #ifndef NDEBUG
263  static void show_send(const std::string &message);
264 #endif
265 
266  void reset_download_to();
267  void close_download_stream();
268  void reset_to_new();
269  void reset_body_stream();
270  void close_connection();
271 
272  static bool more_useful_status_code(int a, int b);
273 
274 public:
275  // This is declared public solely so we can make an ostream operator for it.
276  enum State {
277  S_new,
278  S_try_next_proxy,
279  S_connecting,
280  S_connecting_wait,
281  S_http_proxy_ready,
282  S_http_proxy_request_sent,
283  S_http_proxy_reading_header,
284  S_socks_proxy_greet,
285  S_socks_proxy_greet_reply,
286  S_socks_proxy_connect,
287  S_socks_proxy_connect_reply,
288  S_setup_ssl,
289  S_ssl_handshake,
290  S_ready,
291  S_request_sent,
292  S_reading_header,
293  S_start_direct_file_read,
294  S_read_header,
295  S_begin_body,
296  S_reading_body,
297  S_read_body,
298  S_read_trailer,
299  S_failure
300  };
301 
302 private:
303  class StatusEntry {
304  public:
305  INLINE StatusEntry();
306  int _status_code;
307  std::string _status_string;
308  };
309  typedef pvector<URLSpec> Proxies;
310  typedef pvector<StatusEntry> StatusList;
311 
312  HTTPClient *_client;
313  Proxies _proxies;
314  size_t _proxy_next_index;
315  StatusList _status_list;
316  URLSpec _proxy;
317  PT(BioPtr) _bio;
318  PT(BioStreamPtr) _source;
319  bool _persistent_connection;
320  bool _allow_proxy;
321  bool _proxy_tunnel;
322  double _connect_timeout;
323  double _http_timeout;
324  size_t _skip_body_size;
325  double _idle_timeout;
326  bool _blocking_connect;
327  bool _download_throttle;
328  double _max_bytes_per_second;
329  double _max_updates_per_second;
330  double _seconds_per_update;
331  int _bytes_per_update;
332  bool _nonblocking;
333  bool _wanted_nonblocking;
334  std::string _send_extra_headers;
335 
336  DocumentSpec _document_spec;
337  DocumentSpec _request;
338  HTTPEnum::Method _method;
339  std::string request_path;
340  std::string _header;
341  std::string _body;
342  std::string _content_type;
343  bool _want_ssl;
344  bool _proxy_serves_document;
345  bool _proxy_tunnel_now;
346  bool _server_response_has_no_body;
347  size_t _first_byte_requested;
348  size_t _last_byte_requested;
349  size_t _first_byte_delivered;
350  size_t _last_byte_delivered;
351  int _connect_count;
352 
353  enum DownloadDest {
354  DD_none,
355  DD_file,
356  DD_ram,
357  DD_stream,
358  };
359  DownloadDest _download_dest;
360  bool _subdocument_resumes;
361  Filename _download_to_filename;
362  Ramfile *_download_to_ramfile;
363  std::ostream *_download_to_stream;
364 
365  int _read_index;
366 
367  HTTPEnum::HTTPVersion _http_version;
368  std::string _http_version_string;
369  StatusEntry _status_entry;
370  URLSpec _redirect;
371 
372  std::string _proxy_realm;
373  std::string _proxy_username;
374  PT(HTTPAuthorization) _proxy_auth;
375 
376  std::string _www_realm;
377  std::string _www_username;
378  PT(HTTPAuthorization) _www_auth;
379 
380  // What type of response do we get to our HTTP request?
381  enum ResponseType {
382  RT_none,
383  RT_hangup, // immediately lost connection
384  RT_non_http, // something that wasn't an expected HTTP response
385  RT_http_hangup, // the start of an HTTP response, then a lost connection
386  RT_http_complete // a valid HTTP response completed
387  };
388  ResponseType _response_type;
389 
390  // Not a phash_map, to maintain sorted order.
391  typedef pmap<std::string, std::string> Headers;
392  Headers _headers;
393 
394  size_t _expected_file_size;
395  size_t _file_size;
396  size_t _transfer_file_size;
397  size_t _bytes_downloaded;
398  size_t _bytes_requested;
399  bool _got_expected_file_size;
400  bool _got_file_size;
401  bool _got_transfer_file_size;
402 
403  // These members are used to maintain the current state while communicating
404  // with the server. We need to store everything in the class object instead
405  // of using local variables because in the case of nonblocking IO we have to
406  // be able to return to the caller after any IO operation and resume later
407  // where we left off.
408  State _state;
409  State _done_state;
410  double _started_connecting_time;
411  double _sent_request_time;
412  bool _started_download;
413  std::string _proxy_header;
414  std::string _proxy_request_text;
415  std::string _request_text;
416  std::string _working_get;
417  size_t _sent_so_far;
418  std::string _current_field_name;
419  std::string _current_field_value;
420  ISocketStream *_body_stream;
421  bool _owns_body_stream;
422  BIO *_sbio;
423  std::string _cipher_list;
424  pvector<URLSpec> _redirect_trail;
425  int _last_status_code;
426  double _last_run_time;
427 
428  // RAU we find that we may need a little more time for the ssl handshake
429  // when the phase files are downloading
430  double _extra_ssl_handshake_time;
431 
432 public:
433  virtual TypeHandle get_type() const {
434  return get_class_type();
435  }
436  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
437  static TypeHandle get_class_type() {
438  return _type_handle;
439  }
440  static void init_type() {
441  TypedReferenceCount::init_type();
442  register_type(_type_handle, "HTTPChannel",
443  TypedReferenceCount::get_class_type());
444  }
445 
446 private:
447  static TypeHandle _type_handle;
448  friend class ChunkedStreamBuf;
449  friend class IdentityStreamBuf;
450  friend class HTTPClient;
451 };
452 
453 std::ostream &operator << (std::ostream &out, HTTPChannel::State state);
454 
455 #include "httpChannel.I"
456 
457 #endif // HAVE_OPENSSL
458 
459 #endif
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for a URL, e.g.
Definition: urlSpec.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void register_type(TypeHandle &type_handle, const std::string &name)
This inline function is just a convenient way to call TypeRegistry::register_type(),...
Definition: register_type.I:22
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 base class for things which need to inherit from both TypedObject and from ReferenceCount.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
An in-memory buffer specifically designed for downloading files to memory.
Definition: ramfile.h:25
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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