Panda3D
|
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