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