Panda3D
 All Classes Functions Variables Enumerations
httpChannel.h
00001 // Filename: httpChannel.h
00002 // Created by:  drose (24Sep02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #ifndef HTTPCHANNEL_H
00016 #define HTTPCHANNEL_H
00017 
00018 #include "pandabase.h"
00019 
00020 // This module requires OpenSSL to compile, even if you do not intend
00021 // to use this to establish https connections; this is because it uses
00022 // the OpenSSL library to portably handle all of the socket
00023 // communications.
00024 
00025 #ifdef HAVE_OPENSSL
00026 #define OPENSSL_NO_KRB5
00027 
00028 #include "httpClient.h"
00029 #include "httpEnum.h"
00030 #include "urlSpec.h"
00031 #include "documentSpec.h"
00032 #include "bioPtr.h"
00033 #include "bioStreamPtr.h"
00034 #include "pmap.h"
00035 #include "pvector.h"
00036 #include "pointerTo.h"
00037 #include "config_downloader.h"
00038 #include "filename.h"
00039 #include "openSSLWrapper.h"  // must be included before any other openssl.
00040 #include "openssl/ssl.h"
00041 #include "typedReferenceCount.h"
00042 
00043 class Ramfile;
00044 class HTTPClient;
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //       Class : HTTPChannel
00048 // Description : A single channel of communication from an HTTPClient.
00049 //               This is similar to the concept of a 'connection',
00050 //               except that HTTP is technically connectionless; in
00051 //               fact, a channel may represent one unbroken connection
00052 //               or it may transparently close and reopen a new
00053 //               connection with each request.
00054 //
00055 //               A channel is conceptually a single thread of I/O.
00056 //               One document at a time may be requested using a
00057 //               channel; a new document may (in general) not be
00058 //               requested from the same HTTPChannel until the first
00059 //               document has been fully retrieved.
00060 ////////////////////////////////////////////////////////////////////
00061 class EXPCL_PANDAEXPRESS HTTPChannel : public TypedReferenceCount {
00062 private:
00063   HTTPChannel(HTTPClient *client);
00064 
00065 public:
00066   virtual ~HTTPChannel();
00067 
00068 PUBLISHED:
00069   // get_status_code() will either return an HTTP-style status code >=
00070   // 100 (e.g. 404), or one of the following values.  In general,
00071   // these are ordered from less-successful to more-successful.
00072   enum StatusCode {
00073     SC_incomplete = 0,
00074     SC_internal_error,
00075     SC_no_connection,
00076     SC_timeout,
00077     SC_lost_connection,
00078     SC_non_http_response,
00079     SC_invalid_http,
00080     SC_socks_invalid_version,
00081     SC_socks_no_acceptable_login_method,
00082     SC_socks_refused,
00083     SC_socks_no_connection,
00084     SC_ssl_internal_failure,
00085     SC_ssl_no_handshake,
00086 
00087     // No one returns this code, but StatusCode values higher than
00088     // this are deemed more successful than any generic HTTP response.
00089     SC_http_error_watermark,
00090 
00091     SC_ssl_invalid_server_certificate,
00092     SC_ssl_self_signed_server_certificate,
00093     SC_ssl_unexpected_server,
00094     
00095     // These errors are only generated after a download_to_*() call
00096     // been issued.
00097     SC_download_open_error,
00098     SC_download_write_error,
00099     SC_download_invalid_range,
00100   };
00101 
00102   INLINE HTTPClient *get_client() const;
00103 
00104   INLINE bool is_valid() const;
00105   INLINE bool is_connection_ready() const;
00106 
00107   INLINE const URLSpec &get_url() const;
00108   INLINE const DocumentSpec &get_document_spec() const;
00109   INLINE HTTPEnum::HTTPVersion get_http_version() const;
00110   INLINE const string &get_http_version_string() const;
00111   INLINE int get_status_code() const;
00112   string get_status_string() const;
00113   INLINE const string &get_www_realm() const;
00114   INLINE const string &get_proxy_realm() const;
00115   INLINE const URLSpec &get_redirect() const;
00116   string get_header_value(const string &key) const;
00117 
00118   INLINE int get_num_redirect_steps() const;
00119   INLINE const URLSpec &get_redirect_step(int n) const;
00120   MAKE_SEQ(get_redirect_steps, get_num_redirect_steps, get_redirect_step);
00121 
00122   INLINE void set_persistent_connection(bool persistent_connection);
00123   INLINE bool get_persistent_connection() const;
00124   bool will_close_connection() const;
00125 
00126   INLINE void set_allow_proxy(bool allow_proxy);
00127   INLINE bool get_allow_proxy() const;
00128   INLINE void set_proxy_tunnel(bool proxy_tunnel);
00129   INLINE bool get_proxy_tunnel() const;
00130 
00131   INLINE void set_connect_timeout(double timeout_seconds);
00132   INLINE double get_connect_timeout() const;
00133   INLINE void set_blocking_connect(bool blocking_connect);
00134   INLINE bool get_blocking_connect() const;
00135 
00136   INLINE void set_http_timeout(double timeout_seconds);
00137   INLINE double get_http_timeout() const;
00138 
00139   INLINE void set_skip_body_size(size_t skip_body_size);
00140   INLINE size_t get_skip_body_size() const;
00141   INLINE void set_idle_timeout(double idle_timeout);
00142   INLINE double get_idle_timeout() const;
00143 
00144   INLINE void set_download_throttle(bool download_throttle);
00145   INLINE bool get_download_throttle() const;
00146 
00147   INLINE void set_max_bytes_per_second(double max_bytes_per_second);
00148   INLINE double get_max_bytes_per_second() const;
00149 
00150   INLINE void set_max_updates_per_second(double max_updates_per_second);
00151   INLINE double get_max_updates_per_second() const;
00152 
00153   INLINE void set_expected_file_size(size_t file_size);
00154   off_t get_file_size() const;
00155   INLINE bool is_file_size_known() const;
00156 
00157   INLINE size_t get_first_byte_requested() const;
00158   INLINE size_t get_last_byte_requested() const;
00159   INLINE size_t get_first_byte_delivered() const;
00160   INLINE size_t get_last_byte_delivered() const;
00161 
00162   void write_headers(ostream &out) const;
00163 
00164   INLINE void reset();
00165   INLINE void preserve_status();
00166 
00167   INLINE void clear_extra_headers();
00168   INLINE void send_extra_header(const string &key, const string &value);
00169 
00170   BLOCKING INLINE bool get_document(const DocumentSpec &url);
00171   BLOCKING INLINE bool get_subdocument(const DocumentSpec &url, 
00172                                        size_t first_byte, size_t last_byte);
00173   BLOCKING INLINE bool get_header(const DocumentSpec &url);
00174   BLOCKING INLINE bool post_form(const DocumentSpec &url, const string &body);
00175   BLOCKING INLINE bool put_document(const DocumentSpec &url, const string &body);
00176   BLOCKING INLINE bool delete_document(const DocumentSpec &url);
00177   BLOCKING INLINE bool get_trace(const DocumentSpec &url);
00178   BLOCKING INLINE bool connect_to(const DocumentSpec &url);
00179   BLOCKING INLINE bool get_options(const DocumentSpec &url);
00180 
00181   INLINE void begin_get_document(const DocumentSpec &url);
00182   INLINE void begin_get_subdocument(const DocumentSpec &url, 
00183                                     size_t first_byte, size_t last_byte);
00184   INLINE void begin_get_header(const DocumentSpec &url);
00185   INLINE void begin_post_form(const DocumentSpec &url, const string &body);
00186   bool run();
00187   INLINE void begin_connect_to(const DocumentSpec &url);
00188 
00189   ISocketStream *open_read_body();
00190   void close_read_body(istream *stream) const;
00191 
00192   BLOCKING bool download_to_file(const Filename &filename, bool subdocument_resumes = true);
00193   BLOCKING bool download_to_ram(Ramfile *ramfile, bool subdocument_resumes = true);
00194   BLOCKING bool download_to_stream(ostream *strm, bool subdocument_resumes = true);
00195   SocketStream *get_connection();
00196 
00197   INLINE size_t get_bytes_downloaded() const;
00198   INLINE size_t get_bytes_requested() const;
00199   INLINE bool is_download_complete() const;
00200 
00201 public:
00202   static string downcase(const string &s);
00203   void body_stream_destructs(ISocketStream *stream);
00204 
00205 private:
00206   bool reached_done_state();
00207   bool run_try_next_proxy();
00208   bool run_connecting();
00209   bool run_connecting_wait();
00210   bool run_http_proxy_ready();
00211   bool run_http_proxy_request_sent();
00212   bool run_http_proxy_reading_header();
00213   bool run_socks_proxy_greet();
00214   bool run_socks_proxy_greet_reply();
00215   bool run_socks_proxy_connect();
00216   bool run_socks_proxy_connect_reply();
00217   bool run_setup_ssl();
00218   bool run_ssl_handshake();
00219   bool run_ready();
00220   bool run_request_sent();
00221   bool run_reading_header();
00222   bool run_start_direct_file_read();
00223   bool run_read_header();
00224   bool run_begin_body();
00225   bool run_reading_body();
00226   bool run_read_body();
00227   bool run_read_trailer();
00228 
00229   bool run_download_to_file();
00230   bool run_download_to_ram();
00231   bool run_download_to_stream();
00232 
00233   void begin_request(HTTPEnum::Method method, const DocumentSpec &url, 
00234                      const string &body, bool nonblocking,
00235                      size_t first_byte, size_t last_byte);
00236   void reconsider_proxy();
00237   void reset_for_new_request();
00238 
00239   void finished_body(bool has_trailer);
00240   bool open_download_file();
00241 
00242   bool server_getline(string &str);
00243   bool server_getline_failsafe(string &str);
00244   bool server_get(string &str, size_t num_bytes);
00245   bool server_get_failsafe(string &str, size_t num_bytes);
00246   bool server_send(const string &str, bool secret);
00247   bool parse_http_response(const string &line);
00248   bool parse_http_header();
00249   bool parse_content_range(const string &content_range);
00250 
00251   void check_socket();
00252 
00253   void check_preapproved_server_certificate(X509 *cert, bool &cert_preapproved, 
00254                                             bool &cert_name_preapproved) const;
00255   bool validate_server_name(X509 *cert);
00256   static bool match_cert_name(const string &cert_name, const string &hostname);
00257   static string get_x509_name_component(X509_NAME *name, int nid);
00258 
00259   void make_header();
00260   void make_proxy_request_text();
00261   void make_request_text();
00262 
00263   void reset_url(const URLSpec &old_url, const URLSpec &new_url);
00264   void store_header_field(const string &field_name, const string &field_value);
00265 
00266 #ifndef NDEBUG
00267   static void show_send(const string &message);
00268 #endif
00269 
00270   void reset_download_to();
00271   void close_download_stream();
00272   void reset_to_new();
00273   void reset_body_stream();
00274   void close_connection();
00275 
00276   static bool more_useful_status_code(int a, int b);
00277 
00278 public:
00279   // This is declared public solely so we can make an ostream operator
00280   // for it.
00281   enum State {
00282     S_new,
00283     S_try_next_proxy,
00284     S_connecting,
00285     S_connecting_wait,
00286     S_http_proxy_ready,
00287     S_http_proxy_request_sent,
00288     S_http_proxy_reading_header,
00289     S_socks_proxy_greet,
00290     S_socks_proxy_greet_reply,
00291     S_socks_proxy_connect,
00292     S_socks_proxy_connect_reply,
00293     S_setup_ssl,
00294     S_ssl_handshake,
00295     S_ready,
00296     S_request_sent,
00297     S_reading_header,
00298     S_start_direct_file_read,
00299     S_read_header,
00300     S_begin_body,
00301     S_reading_body,
00302     S_read_body,
00303     S_read_trailer,
00304     S_failure
00305   };
00306 
00307 private:
00308   class StatusEntry {
00309   public:
00310     INLINE StatusEntry();
00311     int _status_code;
00312     string _status_string;
00313   };
00314   typedef pvector<URLSpec> Proxies;
00315   typedef pvector<StatusEntry> StatusList;
00316 
00317   HTTPClient *_client;
00318   Proxies _proxies;
00319   size_t _proxy_next_index;
00320   StatusList _status_list;
00321   URLSpec _proxy;
00322   PT(BioPtr) _bio;
00323   PT(BioStreamPtr) _source;
00324   bool _persistent_connection;
00325   bool _allow_proxy;
00326   bool _proxy_tunnel;
00327   double _connect_timeout;
00328   double _http_timeout;
00329   size_t _skip_body_size;
00330   double _idle_timeout;
00331   bool _blocking_connect;
00332   bool _download_throttle;
00333   double _max_bytes_per_second;
00334   double _max_updates_per_second;
00335   double _seconds_per_update;
00336   int _bytes_per_update;
00337   bool _nonblocking;
00338   bool _wanted_nonblocking;
00339   string _send_extra_headers;
00340 
00341   DocumentSpec _document_spec;
00342   DocumentSpec _request;
00343   HTTPEnum::Method _method;
00344   string request_path;
00345   string _header;
00346   string _body;
00347   bool _want_ssl;
00348   bool _proxy_serves_document;
00349   bool _proxy_tunnel_now;
00350   bool _server_response_has_no_body;
00351   size_t _first_byte_requested;
00352   size_t _last_byte_requested;
00353   size_t _first_byte_delivered;
00354   size_t _last_byte_delivered;
00355   int _connect_count;
00356 
00357   enum DownloadDest {
00358     DD_none,
00359     DD_file,
00360     DD_ram,
00361     DD_stream,
00362   };
00363   DownloadDest _download_dest;
00364   bool _subdocument_resumes;
00365   Filename _download_to_filename;
00366   Ramfile *_download_to_ramfile;
00367   ostream *_download_to_stream;
00368 
00369   int _read_index;
00370 
00371   HTTPEnum::HTTPVersion _http_version;
00372   string _http_version_string;
00373   StatusEntry _status_entry;
00374   URLSpec _redirect;
00375 
00376   string _proxy_realm;
00377   string _proxy_username;
00378   PT(HTTPAuthorization) _proxy_auth;
00379 
00380   string _www_realm;
00381   string _www_username;
00382   PT(HTTPAuthorization) _www_auth;
00383 
00384   // What type of response do we get to our HTTP request?
00385   enum ResponseType {
00386     RT_none,
00387     RT_hangup,       // immediately lost connection 
00388     RT_non_http,     // something that wasn't an expected HTTP response
00389     RT_http_hangup,  // the start of an HTTP response, then a lost connection
00390     RT_http_complete // a valid HTTP response completed
00391   };
00392   ResponseType _response_type;
00393   
00394   // Not a phash_map, to maintain sorted order.
00395   typedef pmap<string, string> Headers;
00396   Headers _headers;
00397 
00398   size_t _expected_file_size;
00399   size_t _file_size;
00400   size_t _transfer_file_size;
00401   size_t _bytes_downloaded;
00402   size_t _bytes_requested;
00403   bool _got_expected_file_size;
00404   bool _got_file_size;
00405   bool _got_transfer_file_size;
00406 
00407   // These members are used to maintain the current state while
00408   // communicating with the server.  We need to store everything in
00409   // the class object instead of using local variables because in the
00410   // case of nonblocking I/O we have to be able to return to the
00411   // caller after any I/O operation and resume later where we left
00412   // off.
00413   State _state;
00414   State _done_state;
00415   double _started_connecting_time;
00416   double _sent_request_time;
00417   bool _started_download;
00418   string _proxy_header;
00419   string _proxy_request_text;
00420   string _request_text;
00421   string _working_get;
00422   size_t _sent_so_far;
00423   string _current_field_name;
00424   string _current_field_value;
00425   ISocketStream *_body_stream;
00426   bool _owns_body_stream;
00427   BIO *_sbio;
00428   string _cipher_list;
00429   pvector<URLSpec> _redirect_trail;
00430   int _last_status_code;
00431   double _last_run_time;
00432 
00433   // RAU we find that we may need a little more time for the
00434   // ssl handshake when the phase files are downloading
00435   double _extra_ssl_handshake_time;
00436 
00437 public:
00438   virtual TypeHandle get_type() const {
00439     return get_class_type();
00440   }
00441   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
00442   static TypeHandle get_class_type() {
00443     return _type_handle;
00444   }
00445   static void init_type() {
00446     TypedReferenceCount::init_type();
00447     register_type(_type_handle, "HTTPChannel",
00448                   TypedReferenceCount::get_class_type());
00449   }
00450 
00451 private:
00452   static TypeHandle _type_handle;
00453   friend class ChunkedStreamBuf;
00454   friend class IdentityStreamBuf;
00455   friend class HTTPClient;
00456 };
00457 
00458 ostream &operator << (ostream &out, HTTPChannel::State state);
00459 
00460 #include "httpChannel.I"
00461 
00462 #endif  // HAVE_OPENSSL
00463 
00464 #endif
00465 
00466 
 All Classes Functions Variables Enumerations