Panda3D

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