32 #if defined(WIN32_VC) || defined(WIN64_VC)    41 using std::ostringstream;
    46 #define _NOTIFY_HTTP_CHANNEL_ID   "[" << this << "] "    52 HTTPChannel(HTTPClient *client) :
    55   if (downloader_cat.is_debug()) {
    56     downloader_cat.debug()
    57       << _NOTIFY_HTTP_CHANNEL_ID
    62     (
"extra-ssl-handshake-time", 0.0,
    63      PRC_DESC(
"This specifies how much extra time to try to establish"    64                "the ssl handshake before we bail."));
    65   _extra_ssl_handshake_time = extra_ssl_handshake_time;
    66   _proxy_next_index = 0;
    67   _persistent_connection = 
false;
    69   _proxy_tunnel = http_proxy_tunnel;
    70   _connect_timeout = http_connect_timeout;
    71   _http_timeout = http_timeout;
    72   _skip_body_size = http_skip_body_size;
    73   _idle_timeout = http_idle_timeout;
    74   _blocking_connect = 
false;
    75   _download_throttle = download_throttle;
    76   _max_bytes_per_second = downloader_byte_rate;
    77   _seconds_per_update = downloader_frequency;
    78   _max_updates_per_second = 1.0f / _seconds_per_update;
    79   _bytes_per_update = int(_max_bytes_per_second * _seconds_per_update);
    87   _wanted_nonblocking = 
false;
    90   _proxy_serves_document = 
false;
    91   _proxy_tunnel_now = 
false;
    92   _first_byte_requested = 0;
    93   _last_byte_requested = 0;
    94   _first_byte_delivered = 0;
    95   _last_byte_delivered = 0;
    97   _expected_file_size = 0;
    99   _transfer_file_size = 0;
   100   _got_expected_file_size = 
false;
   101   _got_file_size = 
false;
   102   _got_transfer_file_size = 
false;
   103   _bytes_downloaded = 0;
   104   _bytes_requested = 0;
   105   _status_entry = StatusEntry();
   106   _response_type = RT_none;
   107   _http_version = _client->get_http_version();
   108   _http_version_string = _client->get_http_version_string();
   109   _content_type = 
"application/x-www-form-urlencoded";
   112   _started_download = 
false;
   114   _body_stream = 
nullptr;
   115   _owns_body_stream = 
false;
   117   _cipher_list = _client->get_cipher_list();
   118   _last_status_code = 0;
   119   _last_run_time = 0.0f;
   120   _download_to_ramfile = 
nullptr;
   121   _download_to_stream = 
nullptr;
   129   if (downloader_cat.is_debug()) {
   130     downloader_cat.debug()
   131       << _NOTIFY_HTTP_CHANNEL_ID
   144 get_status_string()
 const {
   145   switch (_status_entry._status_code) {
   147     return "Connection in progress";
   149   case SC_internal_error:
   150     return "Internal error";
   152   case SC_no_connection:
   153     return "No connection";
   156     return "Timeout on connection";
   158   case SC_lost_connection:
   159     return "Lost connection";
   161   case SC_non_http_response:
   162     return "Non-HTTP response";
   164   case SC_invalid_http:
   165     return "Could not understand HTTP response";
   167   case SC_socks_invalid_version:
   168     return "Unsupported SOCKS version";
   170   case SC_socks_no_acceptable_login_method:
   171     return "No acceptable SOCKS login method";
   173   case SC_socks_refused:
   174     return "SOCKS proxy refused connection";
   176   case SC_socks_no_connection:
   177     return "SOCKS proxy unable to connect";
   179   case SC_ssl_internal_failure:
   180     return "SSL internal failure";
   182   case SC_ssl_no_handshake:
   183     return "No SSL handshake";
   185   case SC_http_error_watermark:
   187     return "Internal error";
   189   case SC_ssl_invalid_server_certificate:
   190     return "SSL invalid server certificate";
   192   case SC_ssl_unexpected_server:
   193     return "Unexpected SSL server";
   195   case SC_download_open_error:
   196     return "Error opening file";
   198   case SC_download_write_error:
   199     return "Error writing to disk";
   201   case SC_download_invalid_range:
   202     return "Invalid subrange requested";
   205   return _status_entry._status_string;
   213 get_header_value(
const string &key)
 const {
   214   Headers::const_iterator hi = _headers.find(
downcase(key));
   215   if (hi != _headers.end()) {
   227 will_close_connection()
 const {
   228   if (get_http_version() < HTTPEnum::HV_11) {
   233   string connection = get_header_value(
"Connection");
   234   if (
downcase(connection) == 
"close") {
   239   if (connection.empty() && !get_persistent_connection()) {
   259 std::streamsize HTTPChannel::
   260 get_file_size()
 const {
   261   if (_got_file_size) {
   263   } 
else if (_got_transfer_file_size) {
   264     return _transfer_file_size;
   265   } 
else if (_got_expected_file_size) {
   266     return _expected_file_size;
   277 write_headers(ostream &out)
 const {
   278   Headers::const_iterator hi;
   279   for (hi = _headers.begin(); hi != _headers.end(); ++hi) {
   280     out << (*hi).first << 
": " << (*hi).second << 
"\n";
   296   if (downloader_cat.is_spam()) {
   297     downloader_cat.spam()
   298       << _NOTIFY_HTTP_CHANNEL_ID
   302   if (_state == _done_state || _state == S_failure) {
   303     clear_extra_headers();
   304     if (!reached_done_state()) {
   309   if (_started_download) {
   310     if (_wanted_nonblocking && _download_throttle) {
   312       double elapsed = now - _last_run_time;
   313       if (elapsed < _seconds_per_update) {
   318       int num_potential_updates = (int)(elapsed / _seconds_per_update);
   319       _last_run_time = now;
   320       _bytes_requested += _bytes_per_update * num_potential_updates;
   321       if (downloader_cat.is_spam()) {
   322         downloader_cat.spam()
   323           << _NOTIFY_HTTP_CHANNEL_ID
   324           << 
"elapsed = " << elapsed << 
" num_potential_updates = "   325           << num_potential_updates << 
" bytes_requested = "   326           << _bytes_requested << 
"\n";
   330     bool repeat_later = 
false;
   331     switch (_download_dest) {
   337       repeat_later = run_download_to_file();
   341       repeat_later = run_download_to_ram();
   345       repeat_later = run_download_to_stream();
   363   if (_state == _done_state) {
   364     return reached_done_state();
   372     if (_bio.is_null() && _state != S_try_next_proxy) {
   373       if (_connect_count > http_max_connect_count) {
   378         downloader_cat.warning()
   379           << _NOTIFY_HTTP_CHANNEL_ID
   380           << 
"Too many lost connections, giving up.\n";
   381         _status_entry._status_code = SC_lost_connection;
   388       if (_proxy.empty()) {
   393       _bio = 
new BioPtr(url);
   394       _source = 
new BioStreamPtr(
new BioStream(_bio));
   396         _bio->set_nbio(
true);
   399       if (downloader_cat.is_debug()) {
   400         if (_connect_count > 0) {
   401           downloader_cat.debug()
   402             << _NOTIFY_HTTP_CHANNEL_ID
   403             << 
"Reconnecting to " << _bio->get_server_name() << 
" port "   404             << _bio->get_port() << 
"\n";
   406           downloader_cat.debug()
   407             << _NOTIFY_HTTP_CHANNEL_ID
   408             << 
"Connecting to " << _bio->get_server_name() << 
" port "   409             << _bio->get_port() << 
"\n";
   413       _state = S_connecting;
   414       _started_connecting_time =
   428     case S_try_next_proxy:
   429       repeat_later = run_try_next_proxy();
   433       repeat_later = run_connecting();
   436     case S_connecting_wait:
   437       repeat_later = run_connecting_wait();
   440     case S_http_proxy_ready:
   441       repeat_later = run_http_proxy_ready();
   444     case S_http_proxy_request_sent:
   445       repeat_later = run_http_proxy_request_sent();
   448     case S_http_proxy_reading_header:
   449       repeat_later = run_http_proxy_reading_header();
   452     case S_socks_proxy_greet:
   453       repeat_later = run_socks_proxy_greet();
   456     case S_socks_proxy_greet_reply:
   457       repeat_later = run_socks_proxy_greet_reply();
   460     case S_socks_proxy_connect:
   461       repeat_later = run_socks_proxy_connect();
   464     case S_socks_proxy_connect_reply:
   465       repeat_later = run_socks_proxy_connect_reply();
   469       repeat_later = run_setup_ssl();
   472     case S_ssl_handshake:
   473       repeat_later = run_ssl_handshake();
   477       repeat_later = run_ready();
   481       repeat_later = run_request_sent();
   484     case S_reading_header:
   485       repeat_later = run_reading_header();
   488     case S_start_direct_file_read:
   489       repeat_later = run_start_direct_file_read();
   493       repeat_later = run_read_header();
   497       repeat_later = run_begin_body();
   501       repeat_later = run_reading_body();
   505       repeat_later = run_read_body();
   509       repeat_later = run_read_trailer();
   513       downloader_cat.warning()
   514         << _NOTIFY_HTTP_CHANNEL_ID
   515         << 
"Unhandled state " << _state << 
"\n";
   519     if (_state == _done_state || _state == S_failure) {
   520       clear_extra_headers();
   522       return reached_done_state();
   524     thread_consider_yield();
   525   } 
while (!repeat_later || _bio.is_null());
   553 ISocketStream *HTTPChannel::
   557   if ((_state != S_read_header && _state != S_begin_body) || _source.is_null()) {
   561   string transfer_coding = 
downcase(get_header_value(
"Transfer-Encoding"));
   563   ISocketStream *result;
   564   if (transfer_coding == 
"chunked") {
   568     _state = S_reading_body;
   570     result = 
new IChunkedStream(_source, 
this);
   577     _state = S_reading_body;
   579     result = 
new IIdentityStream(_source, 
this, _got_file_size, _file_size);
   582   result->_channel = 
this;
   583   _body_stream = result;
   584   _owns_body_stream = 
false;
   596 close_read_body(istream *stream)
 const {
   597   if (stream != 
nullptr) {
   602 #if !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)   604     (*global_operator_delete)(stream);
   636 download_to_file(
const Filename &filename, 
bool subdocument_resumes) {
   638   _download_to_filename = filename;
   640   _subdocument_resumes = subdocument_resumes;
   642   _download_dest = DD_file;
   644   if (_wanted_nonblocking && _state != S_read_header) {
   651   if (!open_download_file()) {
   658   return is_download_complete() && is_valid();
   685 download_to_ram(
Ramfile *ramfile, 
bool subdocument_resumes) {
   686   nassertr(ramfile != 
nullptr, 
false);
   689   _download_to_ramfile = ramfile;
   690   _download_dest = DD_ram;
   691   _subdocument_resumes = (subdocument_resumes && _first_byte_delivered != 0);
   693   if (_wanted_nonblocking && _state != S_read_header) {
   700   if (!open_download_file()) {
   707   return is_download_complete() && is_valid();
   735 download_to_stream(ostream *strm, 
bool subdocument_resumes) {
   737   _download_to_stream = strm;
   738   _download_to_stream->clear();
   739   _subdocument_resumes = subdocument_resumes;
   741   _download_dest = DD_stream;
   743   if (_wanted_nonblocking && _state != S_read_header) {
   750   if (!open_download_file()) {
   757   return is_download_complete() && is_valid();
   768 SocketStream *HTTPChannel::
   770   if (!is_connection_ready()) {
   774   BioStream *stream = _source->get_stream();
   775   _source->set_stream(
nullptr);
   778   if (downloader_cat.is_debug()) {
   779     downloader_cat.debug()
   780       << _NOTIFY_HTTP_CHANNEL_ID
   781       << 
"passing ownership of connection to caller.\n";
   794   result.reserve(s.size());
   795   string::const_iterator p;
   796   for (p = s.begin(); p != s.end(); ++p) {
   797     result += tolower(*p);
   806 body_stream_destructs(ISocketStream *stream) {
   807   if (stream == _body_stream) {
   808     if (_state == S_reading_body) {
   809       switch (_body_stream->get_read_state()) {
   810       case ISocketStream::RS_complete:
   811         finished_body(
false);
   814       case ISocketStream::RS_error:
   815         _state = HTTPChannel::S_failure;
   816         _status_entry._status_code = HTTPChannel::SC_lost_connection;
   823     _body_stream = 
nullptr;
   824     _owns_body_stream = 
false;
   834 reached_done_state() {
   844   if (_state == S_failure) {
   848     if (!_status_list.empty()) {
   849       _status_list.push_back(_status_entry);
   850       if (downloader_cat.is_debug()) {
   851         downloader_cat.debug()
   852           << _NOTIFY_HTTP_CHANNEL_ID
   853           << 
"Reexamining failure responses.\n";
   856       if (downloader_cat.is_debug()) {
   857         downloader_cat.debug()
   858           << _NOTIFY_HTTP_CHANNEL_ID
   859           << 
"  " << 0 << 
". " << _status_list[0]._status_code << 
" "   860           << _status_list[0]._status_string << 
"\n";
   862       for (
size_t i = 1; i < _status_list.size(); i++) {
   863         if (downloader_cat.is_debug()) {
   864           downloader_cat.debug()
   865             << _NOTIFY_HTTP_CHANNEL_ID
   866             << 
"  " << i << 
". " << _status_list[i]._status_code << 
" "   867             << _status_list[i]._status_string << 
"\n";
   869         if (more_useful_status_code(_status_list[i]._status_code,
   870                                     _status_list[best_i]._status_code)) {
   874       if (downloader_cat.is_debug()) {
   875         downloader_cat.debug()
   876           << _NOTIFY_HTTP_CHANNEL_ID
   877           << 
"chose index " << best_i << 
", above.\n";
   879       _status_entry = _status_list[best_i];
   880       _status_list.clear();
   887   _status_list.clear();
   889   if (_download_dest == DD_none) {
   896     if (_body_stream == 
nullptr) {
   897       if (downloader_cat.is_debug()) {
   898         downloader_cat.debug()
   899           << _NOTIFY_HTTP_CHANNEL_ID
   900           << 
"Unable to download body: " << _request.get_url() << 
"\n";
   905       _owns_body_stream = 
true;
   906       if (_state != S_reading_body) {
   909       _started_download = 
true;
   911       _done_state = S_read_trailer;
   924 run_try_next_proxy() {
   925   if (_proxy_next_index < _proxies.size()) {
   928     _status_list.push_back(_status_entry);
   929     _status_entry = StatusEntry();
   932     _proxy = _proxies[_proxy_next_index];
   933     _proxy_auth = 
nullptr;
   937     _state = S_connecting;
   953   _status_entry = StatusEntry();
   955   if (!_bio->connect()) {
   956     if (_bio->should_retry()) {
   957       _state = S_connecting_wait;
   960     downloader_cat.info()
   961       << _NOTIFY_HTTP_CHANNEL_ID
   962       << 
"Could not connect to " << _bio->get_server_name() << 
" port "   963       << _bio->get_port() << 
"\n";
   964     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
   965     _status_entry._status_code = SC_no_connection;
   966     _state = S_try_next_proxy;
   970   if (downloader_cat.is_debug()) {
   971     downloader_cat.debug()
   972       << _NOTIFY_HTTP_CHANNEL_ID
   973       << 
"Connected to " << _bio->get_server_name() << 
" port "   974       << _bio->get_port() << 
"\n";
   977   if (_proxy_tunnel_now) {
   978     if (_proxy.get_scheme() == 
"socks") {
   979       _state = S_socks_proxy_greet;
   981       _state = S_http_proxy_ready;
   986       _state = S_setup_ssl;
  1000 run_connecting_wait() {
  1002   BIO_get_fd(*_bio, &fd);
  1004     downloader_cat.warning()
  1005       << _NOTIFY_HTTP_CHANNEL_ID
  1006       << 
"nonblocking socket BIO has no file descriptor.\n";
  1008     _status_entry._status_code = SC_internal_error;
  1009     _state = S_try_next_proxy;
  1013   if (downloader_cat.is_spam()) {
  1014     downloader_cat.spam()
  1015       << _NOTIFY_HTTP_CHANNEL_ID
  1016       << 
"waiting to connect to " << _request.get_url().get_server_and_port() << 
".\n";
  1022   if (get_blocking_connect()) {
  1025     tv.tv_sec = (int)_connect_timeout;
  1026     tv.tv_usec = (int)((_connect_timeout - tv.tv_sec) * 1000000.0);
  1032   int errcode = select(fd + 1, 
nullptr, &wset, 
nullptr, &tv);
  1034     downloader_cat.warning()
  1035       << _NOTIFY_HTTP_CHANNEL_ID
  1036       << 
"Error in select.\n";
  1038     _status_entry._status_code = SC_internal_error;
  1039     _state = S_try_next_proxy;
  1045     if (get_blocking_connect() ||
  1047          _started_connecting_time > get_connect_timeout())) {
  1049       downloader_cat.info()
  1050         << _NOTIFY_HTTP_CHANNEL_ID
  1051         << 
"Timeout connecting to "  1052         << _request.get_url().get_server_and_port()
  1053         << 
" for " << _request.get_url()
  1055       _status_entry._status_code = SC_timeout;
  1056       _state = S_try_next_proxy;
  1063   _state = S_connecting;
  1074 run_http_proxy_ready() {
  1076   nassertr(!_proxy_request_text.empty(), 
false);
  1077   if (!server_send(_proxy_request_text, 
false)) {
  1082   _state = S_http_proxy_request_sent;
  1094 run_http_proxy_request_sent() {
  1097   if (!server_getline_failsafe(line)) {
  1102   while (line.empty()) {
  1103     if (!server_getline_failsafe(line)) {
  1108   if (!parse_http_response(line)) {
  1112   _state = S_http_proxy_reading_header;
  1113   _current_field_name = string();
  1114   _current_field_value = string();
  1116   _got_file_size = 
false;
  1117   _got_transfer_file_size = 
false;
  1126 run_http_proxy_reading_header() {
  1127   if (parse_http_header()) {
  1131   _redirect = get_header_value(
"Location");
  1135   _server_response_has_no_body =
  1136     (get_status_code() / 100 == 1 ||
  1137      get_status_code() == 204 ||
  1138      get_status_code() == 304);
  1140   int last_status = _last_status_code;
  1141   _last_status_code = get_status_code();
  1143   if (get_status_code() == 407 && last_status != 407 && !_proxy.empty()) {
  1145     string authenticate_request = get_header_value(
"Proxy-Authenticate");
  1146     _proxy_auth = _client->generate_auth(_proxy, 
true, authenticate_request);
  1147     if (_proxy_auth != 
nullptr) {
  1148       _proxy_realm = _proxy_auth->get_realm();
  1149       _proxy_username = _client->select_username(_proxy, 
true, _proxy_realm);
  1150       if (!_proxy_username.empty()) {
  1151         make_proxy_request_text();
  1154         _state = S_begin_body;
  1166     if (get_status_code() != 407) {
  1167       _status_entry._status_code += 1000;
  1170     _state = S_try_next_proxy;
  1175   make_request_text();
  1178     _state = S_setup_ssl;
  1191 run_socks_proxy_greet() {
  1192   static const char socks_greeting[] = {
  1201   static const int socks_greeting_len = 
sizeof(socks_greeting);
  1202   if (!server_send(
string(socks_greeting, socks_greeting_len), 
true)) {
  1208   _state = S_socks_proxy_greet_reply;
  1216 run_socks_proxy_greet_reply() {
  1220   if (!server_get_failsafe(reply, 2)) {
  1224   if (reply[0] != 0x05) {
  1226     downloader_cat.info()
  1227       << _NOTIFY_HTTP_CHANNEL_ID
  1228       << 
"Rejecting Socks version " << (int)reply[0] << 
"\n";
  1229     _status_entry._status_code = SC_socks_invalid_version;
  1230     _state = S_try_next_proxy;
  1234   if (reply[1] == (
char)0xff) {
  1235     downloader_cat.info()
  1236       << _NOTIFY_HTTP_CHANNEL_ID
  1237       << 
"Socks server does not accept our available login methods.\n";
  1238     _status_entry._status_code = SC_socks_no_acceptable_login_method;
  1239     _state = S_try_next_proxy;
  1243   if (reply[1] == 0x00) {
  1245     _state = S_socks_proxy_connect;
  1250   downloader_cat.info()
  1251     << _NOTIFY_HTTP_CHANNEL_ID
  1252     << 
"Socks server accepted unrequested login method "  1253     << (int)reply[1] << 
"\n";
  1254   _status_entry._status_code = SC_socks_no_acceptable_login_method;
  1255   _state = S_try_next_proxy;
  1263 run_socks_proxy_connect() {
  1264   static const char socks_connect[] = {
  1270   static const int socks_connect_len = 
sizeof(socks_connect);
  1272   string hostname = _request.get_url().get_server();
  1273   int port = _request.get_url().get_port();
  1275   if (downloader_cat.is_debug()) {
  1276     downloader_cat.debug()
  1277       << _NOTIFY_HTTP_CHANNEL_ID
  1278       << 
"Requesting SOCKS5 connection to "  1279       << _request.get_url().get_server_and_port() << 
"\n";
  1283     string(socks_connect, socks_connect_len) +
  1284     string(1, (
char)hostname.length()) +
  1286     string(1, (
char)((port >> 8) & 0xff)) +
  1287     string(1, (
char)(port & 0xff));
  1289   if (!server_send(connect, 
true)) {
  1294   _state = S_socks_proxy_connect_reply;
  1302 run_socks_proxy_connect_reply() {
  1306   if (!server_get_failsafe(reply, 2)) {
  1310   if (reply[0] != 0x05) {
  1312     downloader_cat.info()
  1313       << _NOTIFY_HTTP_CHANNEL_ID
  1314       << 
"Rejecting Socks version " << (int)reply[0] << 
"\n";
  1316     _status_entry._status_code = SC_socks_invalid_version;
  1317     _state = S_try_next_proxy;
  1321   if (reply[1] != 0x00) {
  1322     downloader_cat.info()
  1323       << _NOTIFY_HTTP_CHANNEL_ID
  1324       << 
"Connection refused, SOCKS code " << (int)reply[1] << 
"\n";
  1346       _status_entry._status_code = SC_socks_no_connection;
  1350       _status_entry._status_code = SC_socks_refused;
  1354     _state = S_try_next_proxy;
  1359   _working_get = reply;
  1360   if (!server_get_failsafe(reply, 5)) {
  1365   int total_bytes = 6;
  1373     total_bytes += (
unsigned int)reply[4];
  1381     downloader_cat.info()
  1382       << _NOTIFY_HTTP_CHANNEL_ID
  1383       << 
"Unsupported SOCKS address type: " << (int)reply[3] << 
"\n";
  1384     _status_entry._status_code = SC_socks_invalid_version;
  1385     _state = S_try_next_proxy;
  1390   _working_get = reply;
  1391   if (!server_get_failsafe(reply, total_bytes)) {
  1395   if (downloader_cat.is_debug()) {
  1397     string connect_host;
  1403         strm << (
unsigned int)(
unsigned char)reply[4] << 
"."  1404              << (
unsigned int)(
unsigned char)reply[5] << 
"."  1405              << (
unsigned int)(
unsigned char)reply[6] << 
"."  1406              << (
unsigned int)(
unsigned char)reply[7];
  1407         connect_host = strm.str();
  1412       connect_host = string(&reply[5], (
unsigned int)reply[4]);
  1418         sprintf(buf, 
"[%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx"  1419                      ":%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx:%02hhx%02hhx]",
  1420                 reply[4], reply[5], reply[6], reply[7], reply[8], reply[9],
  1421                 reply[10], reply[11], reply[12], reply[13], reply[14],
  1422                 reply[15], reply[16], reply[17], reply[18], reply[19]);
  1429       (((
unsigned int)(
unsigned char)reply[total_bytes - 2]) << 8) |
  1430       ((
unsigned int)(
unsigned char)reply[total_bytes - 1]);
  1432     downloader_cat.debug()
  1433       << _NOTIFY_HTTP_CHANNEL_ID
  1434       << _proxy << 
" directed us to " << connect_host << 
":"  1435       << connect_port << 
"\n";
  1439     _state = S_setup_ssl;
  1453   _sbio = BIO_new_ssl(_client->get_ssl_ctx(), 
true);
  1454   BIO_push(_sbio, *_bio);
  1457   BIO_get_ssl(_sbio, &ssl);
  1458   nassertr(ssl != 
nullptr, 
false);
  1462   string cipher_list = _cipher_list;
  1463   if (!cipher_list.empty()) {
  1464     size_t space = cipher_list.find(
" ");
  1465     if (space != string::npos) {
  1466       cipher_list = cipher_list.substr(0, space);
  1470   if (downloader_cat.is_debug()) {
  1471     downloader_cat.debug()
  1472       << _NOTIFY_HTTP_CHANNEL_ID
  1473       << 
"Setting ssl-cipher-list '" << cipher_list << 
"'\n";
  1475   int result = SSL_set_cipher_list(ssl, cipher_list.c_str());
  1477     downloader_cat.error()
  1478       << _NOTIFY_HTTP_CHANNEL_ID
  1479       << 
"Invalid cipher list: '" << cipher_list << 
"'\n";
  1480     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
  1481     _status_entry._status_code = SC_ssl_internal_failure;
  1486   string hostname = _request.get_url().get_server();
  1487   result = SSL_set_tlsext_host_name(ssl, hostname.c_str());
  1489     downloader_cat.error()
  1490       << _NOTIFY_HTTP_CHANNEL_ID
  1491       << 
"Could not set TLS SNI hostname to '" << hostname << 
"'\n";
  1503   if (_client->load_client_certificate()) {
  1504     SSL_use_certificate(ssl, _client->_client_certificate_pub);
  1505     SSL_use_PrivateKey(ssl, _client->_client_certificate_priv);
  1506     if (!SSL_check_private_key(ssl)) {
  1507       downloader_cat.warning()
  1508         << _NOTIFY_HTTP_CHANNEL_ID
  1509         << 
"Client private key does not match public key!\n";
  1513   if (downloader_cat.is_spam()) {
  1514     downloader_cat.spam()
  1515       << _NOTIFY_HTTP_CHANNEL_ID
  1516       << 
"SSL Ciphers available:\n";
  1519     name = SSL_get_cipher_list(ssl, pri);
  1520     while (name != 
nullptr) {
  1521       downloader_cat.spam()
  1522         << _NOTIFY_HTTP_CHANNEL_ID
  1523         << 
"  " << pri + 1 << 
". " << name << 
"\n";
  1525       name = SSL_get_cipher_list(ssl, pri);
  1529   if (downloader_cat.is_debug()) {
  1530     downloader_cat.debug()
  1531       << _NOTIFY_HTTP_CHANNEL_ID
  1532       << 
"performing SSL handshake\n";
  1534   _state = S_ssl_handshake;
  1537   _started_connecting_time =
  1548 run_ssl_handshake() {
  1549   if (BIO_do_handshake(_sbio) <= 0) {
  1550     if (BIO_should_retry(_sbio)) {
  1553         _started_connecting_time;
  1554       if (elapsed <= get_connect_timeout() + _extra_ssl_handshake_time) {
  1561     downloader_cat.info()
  1562       << _NOTIFY_HTTP_CHANNEL_ID
  1563       << 
"Could not establish SSL handshake with "  1564       << _request.get_url().get_server_and_port() << 
"\n";
  1565     OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
  1570     if (!_cipher_list.empty()) {
  1572       size_t space = _cipher_list.find(
" ");
  1573       if (space != string::npos) {
  1574         while (space < _cipher_list.length() && _cipher_list[space] == 
' ') {
  1577         _cipher_list = _cipher_list.substr(space);
  1578         if (!_cipher_list.empty()) {
  1581           _state = S_connecting;
  1588     _cipher_list = _client->get_cipher_list();
  1589     _status_entry._status_code = SC_ssl_no_handshake;
  1595   BIO_get_ssl(_sbio, &ssl);
  1596   nassertr(ssl != 
nullptr, 
false);
  1598   if (!_nonblocking) {
  1599     SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
  1602   const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
  1603   if (cipher == 
nullptr) {
  1604     downloader_cat.warning()
  1605       << _NOTIFY_HTTP_CHANNEL_ID
  1606       << 
"No current cipher on SSL connection.\n";
  1608     if (downloader_cat.is_debug()) {
  1609       downloader_cat.debug()
  1610         << _NOTIFY_HTTP_CHANNEL_ID
  1611         << 
"Using cipher " << SSL_CIPHER_get_name((SSL_CIPHER *) cipher) << 
"\n";
  1617   _bio->set_bio(_sbio);
  1620   X509 *cert = SSL_get_peer_certificate(ssl);
  1621   if (cert == 
nullptr) {
  1622     downloader_cat.info()
  1623       << _NOTIFY_HTTP_CHANNEL_ID
  1624       << 
"No certificate was presented by server.\n";
  1627     _status_entry._status_code = SC_ssl_invalid_server_certificate;
  1632   X509_NAME *subject = X509_get_subject_name(cert);
  1633   if (downloader_cat.is_debug()) {
  1634     string org_name = get_x509_name_component(subject, NID_organizationName);
  1635     string org_unit_name = get_x509_name_component(subject, NID_organizationalUnitName);
  1636     string common_name = get_x509_name_component(subject, NID_commonName);
  1638     downloader_cat.debug()
  1639       << _NOTIFY_HTTP_CHANNEL_ID
  1640       << 
"Server is " << common_name << 
" from " << org_unit_name
  1641       << 
" / " << org_name << 
"\n";
  1643     if (downloader_cat.is_spam()) {
  1644       downloader_cat.spam()
  1645         << _NOTIFY_HTTP_CHANNEL_ID
  1646         << 
"Received certificate from server:\n" << std::flush;
  1647       X509_print_fp(stderr, cert);
  1652   bool cert_preapproved = 
false;
  1653   bool cert_name_preapproved = 
false;
  1654   check_preapproved_server_certificate(cert, cert_preapproved, cert_name_preapproved);
  1657   long verify_result = SSL_get_verify_result(ssl);
  1658   bool cert_valid = 
true;
  1660   if (verify_result == X509_V_ERR_CERT_HAS_EXPIRED) {
  1661     downloader_cat.info()
  1662       << _NOTIFY_HTTP_CHANNEL_ID
  1663       << 
"Expired certificate from " << _request.get_url().get_server_and_port() << 
"\n";
  1664     if (_client->get_verify_ssl() == HTTPClient::VS_normal && !cert_preapproved) {
  1668   } 
else if (verify_result == X509_V_ERR_CERT_NOT_YET_VALID) {
  1669     downloader_cat.info()
  1670       << _NOTIFY_HTTP_CHANNEL_ID
  1671       << 
"Premature certificate from " << _request.get_url().get_server_and_port() << 
"\n";
  1672     if (_client->get_verify_ssl() == HTTPClient::VS_normal && !cert_preapproved) {
  1676   } 
else if (verify_result == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
  1677              verify_result == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) {
  1678     downloader_cat.info()
  1679       << _NOTIFY_HTTP_CHANNEL_ID
  1680       << 
"Self-signed certificate from " << _request.get_url().get_server_and_port() << 
"\n";
  1681     if (_client->get_verify_ssl() != HTTPClient::VS_no_verify && !cert_preapproved) {
  1685   } 
else if (verify_result != X509_V_OK) {
  1686     downloader_cat.info()
  1687       << _NOTIFY_HTTP_CHANNEL_ID
  1688       << 
"Unable to verify identity of " << _request.get_url().get_server_and_port()
  1689       << 
", verify error code " << verify_result << 
"\n";
  1690     if (_client->get_verify_ssl() != HTTPClient::VS_no_verify && !cert_preapproved) {
  1696     _status_entry._status_code = SC_ssl_invalid_server_certificate;
  1701   if (_client->get_verify_ssl() != HTTPClient::VS_no_verify && !cert_name_preapproved) {
  1703     if (!validate_server_name(cert)) {
  1704       _status_entry._status_code = SC_ssl_unexpected_server;
  1727   if (!_request_text.empty()) {
  1728    if (!server_send(_request_text, 
false)) {
  1734   _state = S_request_sent;
  1744 run_request_sent() {
  1747   if (!server_getline_failsafe(line)) {
  1752   while (line.empty()) {
  1753     if (!server_getline_failsafe(line)) {
  1758   if (!parse_http_response(line)) {
  1763   _state = S_reading_header;
  1764   _current_field_name = string();
  1765   _current_field_value = string();
  1767   _got_file_size = 
false;
  1768   _got_transfer_file_size = 
false;
  1778 run_reading_header() {
  1779   if (parse_http_header()) {
  1780     if (_bio.is_null()) {
  1781       downloader_cat.info()
  1782         << _NOTIFY_HTTP_CHANNEL_ID
  1783         << 
"Connection lost while reading HTTP response.\n";
  1784       if (_response_type == RT_http_hangup) {
  1786         _status_entry._status_code = SC_lost_connection;
  1787         _state = S_try_next_proxy;
  1791         _response_type = RT_http_hangup;
  1798       if (elapsed > get_http_timeout()) {
  1800         downloader_cat.info()
  1801           << _NOTIFY_HTTP_CHANNEL_ID
  1802           << 
"Timeout waiting for "  1803           << _request.get_url().get_server_and_port()
  1804           << 
" in run_reading_header (" << elapsed
  1805           << 
" seconds elapsed).\n";
  1806         _status_entry._status_code = SC_timeout;
  1807         _state = S_try_next_proxy;
  1812   _response_type = RT_http_complete;
  1816   clear_extra_headers();
  1818   _server_response_has_no_body =
  1819     (get_status_code() / 100 == 1 ||
  1820      get_status_code() == 204 ||
  1821      get_status_code() == 304 ||
  1822      _method == HTTPEnum::M_head);
  1825   if (get_status_code() == 206) {
  1826     string content_range = get_header_value(
"Content-Range");
  1827     if (content_range.empty()) {
  1828       downloader_cat.warning()
  1829         << _NOTIFY_HTTP_CHANNEL_ID
  1830         << 
"Got 206 response without Content-Range header!\n";
  1831       _status_entry._status_code = SC_invalid_http;
  1836       if (!parse_content_range(content_range)) {
  1837         downloader_cat.warning()
  1838           << _NOTIFY_HTTP_CHANNEL_ID
  1839           << 
"Couldn't parse Content-Range: " << content_range << 
"\n";
  1840         _status_entry._status_code = SC_invalid_http;
  1847     _first_byte_delivered = 0;
  1848     _last_byte_delivered = 0;
  1850   if (downloader_cat.is_debug()) {
  1851     if (_first_byte_requested != 0 || _last_byte_requested != 0 ||
  1852         _first_byte_delivered != 0 || _last_byte_delivered != 0) {
  1853       downloader_cat.debug()
  1854         << _NOTIFY_HTTP_CHANNEL_ID
  1855         << 
"Requested byte range " << _first_byte_requested
  1856         << 
" to " << _last_byte_delivered
  1857         << 
"; server delivers range " << _first_byte_delivered
  1858         << 
" to " << _last_byte_delivered
  1865   string tag = get_header_value(
"ETag");
  1869   string date = get_header_value(
"Last-Modified");
  1870   if (!date.empty()) {
  1871     _document_spec.set_date(
HTTPDate(date));
  1877   if (_server_response_has_no_body) {
  1879     reset_download_to();
  1882   if (!open_download_file()) {
  1886   _got_expected_file_size = 
false;
  1887   _got_file_size = 
false;
  1888   _got_transfer_file_size = 
false;
  1890   string content_length = get_header_value(
"Content-Length");
  1891   if (!content_length.empty()) {
  1892     _file_size = atoi(content_length.c_str());
  1893     _got_file_size = 
true;
  1895   } 
else if (get_status_code() == 206) {
  1898     _file_size = _last_byte_delivered - _first_byte_delivered + 1;
  1899     _got_file_size = 
true;
  1901   _redirect = get_header_value(
"Location");
  1906   if (_redirect.has_path() && !_redirect.has_authority()) {
  1908     Filename path = _redirect.get_path();
  1911       _redirect.set_path(
Filename(rel_to, path));
  1917   _state = S_read_header;
  1919   if (_server_response_has_no_body && will_close_connection()) {
  1926   int last_status = _last_status_code;
  1927   _last_status_code = get_status_code();
  1929   if (get_status_code() == 407 && last_status != 407 && !_proxy.empty()) {
  1931     string authenticate_request = get_header_value(
"Proxy-Authenticate");
  1933       _client->generate_auth(_proxy, 
true, authenticate_request);
  1934     if (_proxy_auth != 
nullptr) {
  1935       _proxy_realm = _proxy_auth->get_realm();
  1936       _proxy_username = _client->select_username(_proxy, 
true, _proxy_realm);
  1937       if (!_proxy_username.empty()) {
  1938         make_request_text();
  1941         _state = S_begin_body;
  1947   if (get_status_code() == 401 && last_status != 401) {
  1949     string authenticate_request = get_header_value(
"WWW-Authenticate");
  1950     _www_auth = _client->generate_auth(_request.get_url(), 
false, authenticate_request);
  1951     if (_www_auth != 
nullptr) {
  1952       _www_realm = _www_auth->get_realm();
  1953       _www_username = _client->select_username(_request.get_url(), 
false, _www_realm);
  1954       if (!_www_username.empty()) {
  1955         make_request_text();
  1958         _state = S_begin_body;
  1964   if ((get_status_code() == 300 ||
  1965        get_status_code() == 301 ||
  1966        get_status_code() == 302 ||
  1967        get_status_code() == 303 ||
  1968        get_status_code() == 307) && !get_redirect().empty()) {
  1976     if (_method == HTTPEnum::M_post) {
  1977       _method = HTTPEnum::M_get;
  1981     if (_method == HTTPEnum::M_get || _method == HTTPEnum::M_head) {
  1983       URLSpec new_url = get_redirect();
  1984       if (find(_redirect_trail.begin(), _redirect_trail.end(),
  1985                new_url) != _redirect_trail.end()) {
  1986         downloader_cat.warning()
  1987           << _NOTIFY_HTTP_CHANNEL_ID
  1988           << 
"cycle detected in redirect to " << new_url << 
"\n";
  1991         _redirect_trail.push_back(new_url);
  1993         if (downloader_cat.is_debug()) {
  1994           downloader_cat.debug()
  1995             << _NOTIFY_HTTP_CHANNEL_ID
  1996             << 
"following redirect to " << new_url << 
"\n";
  1998         if (_request.get_url().has_username()) {
  1999           new_url.
set_username(_request.get_url().get_username());
  2001         reset_url(_request.get_url(), new_url);
  2002         _request.set_url(new_url);
  2003         _want_ssl = _request.get_url().is_ssl();
  2006         make_request_text();
  2009         _state = S_begin_body;
  2015   if (_state == S_read_header &&
  2016       ((get_status_code() / 100) == 4 || (get_status_code() / 100) == 5) &&
  2017       _proxy_serves_document && _proxy_next_index < _proxies.size()) {
  2024     _state = S_try_next_proxy;
  2037 run_start_direct_file_read() {
  2038   _state = S_read_header;
  2039   if (!open_download_file()) {
  2059   _state = S_begin_body;
  2069   if (will_close_connection()) {
  2072     if (downloader_cat.is_debug()) {
  2073       downloader_cat.debug()
  2074         << _NOTIFY_HTTP_CHANNEL_ID
  2075         << 
"resetting to begin body; server would close anyway.\n";
  2081   if (_server_response_has_no_body) {
  2083     _state = S_read_trailer;
  2085   } 
else if (get_file_size() > (
int)_skip_body_size) {
  2089     if (downloader_cat.is_debug()) {
  2090       downloader_cat.debug()
  2091         << _NOTIFY_HTTP_CHANNEL_ID
  2092         << 
"Dropping connection rather than skipping past "  2093         << get_file_size() << 
" bytes.\n";
  2099     if (_body_stream == 
nullptr) {
  2100       if (downloader_cat.is_debug()) {
  2101         downloader_cat.debug()
  2102           << _NOTIFY_HTTP_CHANNEL_ID
  2103           << 
"Unable to skip body.\n";
  2108       _owns_body_stream = 
true;
  2109       if (_state != S_reading_body) {
  2110         reset_body_stream();
  2127 run_reading_body() {
  2128   if (will_close_connection()) {
  2131     if (downloader_cat.is_debug()) {
  2132       downloader_cat.debug()
  2133         << _NOTIFY_HTTP_CHANNEL_ID
  2134         << 
"resetting to read body; server would close anyway.\n";
  2141   if (_body_stream == 
nullptr || !_owns_body_stream) {
  2143     if (downloader_cat.is_debug()) {
  2144       downloader_cat.debug()
  2145         << _NOTIFY_HTTP_CHANNEL_ID
  2146         << 
"resetting, not in skip-body mode.\n";
  2153   std::getline(*_body_stream, line);
  2154   while (!_body_stream->fail() && !_body_stream->eof()) {
  2155     if (downloader_cat.is_spam()) {
  2156       downloader_cat.spam()
  2157         << _NOTIFY_HTTP_CHANNEL_ID
  2158         << 
"skip: " << line << 
"\n";
  2160     std::getline(*_body_stream, line);
  2163   if (!_body_stream->is_closed()) {
  2168   reset_body_stream();
  2171   nassertr(_state != S_reading_body, 
false);
  2186   if (will_close_connection()) {
  2189     if (downloader_cat.is_debug()) {
  2190       downloader_cat.debug()
  2191         << _NOTIFY_HTTP_CHANNEL_ID
  2192         << 
"resetting to read body; server would close anyway.\n";
  2200   if (!server_getline(line)) {
  2203   while (!line.empty()) {
  2204     if (!server_getline(line)) {
  2209   _state = S_read_trailer;
  2218 run_read_trailer() {
  2219   if (will_close_connection()) {
  2222     if (downloader_cat.is_debug()) {
  2223       downloader_cat.debug()
  2224         << _NOTIFY_HTTP_CHANNEL_ID
  2225         << 
"resetting to read trailer; server would close anyway.\n";
  2240 run_download_to_file() {
  2241   nassertr(_body_stream != 
nullptr && _owns_body_stream, 
false);
  2243   bool do_throttle = _wanted_nonblocking && _download_throttle;
  2245   static const size_t buffer_size = 4096;
  2246   char buffer[buffer_size];
  2248   size_t remaining_this_pass = buffer_size;
  2250     remaining_this_pass = _bytes_per_update;
  2253   _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2254   size_t count = _body_stream->gcount();
  2255   while (count != 0) {
  2256     _download_to_stream->write(buffer, count);
  2257     _bytes_downloaded += count;
  2259       nassertr(count <= remaining_this_pass, 
false);
  2260       remaining_this_pass -= count;
  2261       if (remaining_this_pass == 0) {
  2267     thread_consider_yield();
  2268     _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2269     count = _body_stream->gcount();
  2272   if (_download_to_stream->fail()) {
  2273     downloader_cat.warning()
  2274       << _NOTIFY_HTTP_CHANNEL_ID
  2275       << 
"Error writing to " << _download_to_filename << 
"\n";
  2276     _status_entry._status_code = SC_download_write_error;
  2278     reset_download_to();
  2282   _download_to_stream->flush();
  2284   if (_body_stream->is_closed()) {
  2286     reset_body_stream();
  2287     close_download_stream();
  2288     _started_download = 
false;
  2301 run_download_to_ram() {
  2302   nassertr(_body_stream != 
nullptr && _owns_body_stream, 
false);
  2303   nassertr(_download_to_ramfile != 
nullptr, 
false);
  2305   bool do_throttle = _wanted_nonblocking && _download_throttle;
  2307   static const size_t buffer_size = 4096;
  2308   char buffer[buffer_size];
  2310   size_t remaining_this_pass = buffer_size;
  2312     remaining_this_pass = _bytes_per_update;
  2315   _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2316   size_t count = _body_stream->gcount();
  2317   while (count != 0) {
  2318     _download_to_ramfile->_data += string(buffer, count);
  2319     _bytes_downloaded += count;
  2321       nassertr(count <= remaining_this_pass, 
false);
  2322       remaining_this_pass -= count;
  2323       if (remaining_this_pass == 0) {
  2329     thread_consider_yield();
  2330     _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2331     count = _body_stream->gcount();
  2334   if (_body_stream->is_closed()) {
  2336     reset_body_stream();
  2337     close_download_stream();
  2338     _started_download = 
false;
  2351 run_download_to_stream() {
  2352   nassertr(_body_stream != 
nullptr && _owns_body_stream, 
false);
  2354   bool do_throttle = _wanted_nonblocking && _download_throttle;
  2356   static const size_t buffer_size = 4096;
  2357   char buffer[buffer_size];
  2359   size_t remaining_this_pass = buffer_size;
  2361     remaining_this_pass = _bytes_per_update;
  2364   _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2365   size_t count = _body_stream->gcount();
  2366   while (count != 0) {
  2367     _download_to_stream->write(buffer, count);
  2368     _bytes_downloaded += count;
  2370       nassertr(count <= remaining_this_pass, 
false);
  2371       remaining_this_pass -= count;
  2372       if (remaining_this_pass == 0) {
  2378     thread_consider_yield();
  2379     _body_stream->read(buffer, min(buffer_size, remaining_this_pass));
  2380     count = _body_stream->gcount();
  2383   if (_download_to_stream->fail()) {
  2384     downloader_cat.warning()
  2385       << _NOTIFY_HTTP_CHANNEL_ID
  2386       << 
"Error writing to stream\n";
  2387     _status_entry._status_code = SC_download_write_error;
  2389     reset_download_to();
  2393   _download_to_stream->flush();
  2395   if (_body_stream->is_closed()) {
  2397     reset_body_stream();
  2398     close_download_stream();
  2399     _started_download = 
false;
  2413 begin_request(HTTPEnum::Method method, 
const DocumentSpec &url,
  2414               const string &body, 
bool nonblocking,
  2415               size_t first_byte, 
size_t last_byte) {
  2417   downloader_cat.info()
  2418     << _NOTIFY_HTTP_CHANNEL_ID
  2419     << 
"begin " << method << 
" " << url << 
"\n";
  2421   reset_for_new_request();
  2423   _wanted_nonblocking = nonblocking;
  2424 #if defined(HAVE_THREADS) && defined(SIMPLE_THREADS)  2432   _proxy_next_index = 0;
  2433   if (get_allow_proxy()) {
  2434     _client->get_proxies_for_url(url.get_url(), _proxies);
  2440   if (!_bio.is_null() && !_proxies.empty() && !_proxy.empty()) {
  2441     Proxies::iterator pi = find(_proxies.begin(), _proxies.end(), _proxy);
  2442     if (pi != _proxies.end()) {
  2444       _proxies.insert(_proxies.begin(), _proxy);
  2449   if (_proxy_next_index < _proxies.size()) {
  2450     new_proxy = _proxies[_proxy_next_index];
  2451     _proxy_next_index++;
  2455   if (_proxy != new_proxy) {
  2457     _proxy_auth = 
nullptr;
  2458     if (downloader_cat.is_debug()) {
  2459       downloader_cat.debug()
  2460         << _NOTIFY_HTTP_CHANNEL_ID
  2461         << 
"resetting to change proxy to " << _proxy << 
"\n";
  2467   if (_nonblocking != nonblocking) {
  2468     _nonblocking = nonblocking;
  2469     if (downloader_cat.is_debug()) {
  2470       downloader_cat.debug()
  2471         << _NOTIFY_HTTP_CHANNEL_ID
  2472         << 
"resetting to change nonblocking state to " << _nonblocking << 
".\n";
  2477   reset_url(_request.get_url(), url.get_url());
  2484   _want_ssl = _request.get_url().is_ssl();
  2486   _first_byte_requested = first_byte;
  2487   _last_byte_requested = last_byte;
  2493   if (_request.get_url().get_scheme() == 
"file") {
  2498     _bio = 
new BioPtr(_request.get_url());
  2499     if (_bio->get_bio() != 
nullptr) {
  2501       _source = 
new BioStreamPtr(
new BioStream(_bio));
  2502       _status_entry._status_code = 200;
  2503       _state = S_start_direct_file_read;
  2507       BIO_get_fp(_bio->get_bio(), &fp);
  2508       if (fp != 
nullptr) {
  2509         if (fseek(fp, 0, SEEK_END) == 0) {
  2510           _file_size = ftell(fp);
  2511           _got_file_size = 
true;
  2512           fseek(fp, 0, SEEK_SET);
  2518       OpenSSLWrapper::get_global_ptr()->notify_ssl_errors();
  2519       _status_entry._status_code = SC_no_connection;
  2525     if (_state == S_failure || (_state < S_read_header && _state != S_ready)) {
  2526       if (downloader_cat.is_debug()) {
  2527         downloader_cat.debug()
  2528           << _NOTIFY_HTTP_CHANNEL_ID
  2529           << 
"resetting to clear previous request.\n";
  2534       if (downloader_cat.is_debug()) {
  2535         downloader_cat.debug()
  2536           << _NOTIFY_HTTP_CHANNEL_ID
  2537           << 
"resetting old connection: "  2543     } 
else if (_state == S_read_header) {
  2545       _state = S_begin_body;
  2549   if (_method == HTTPEnum::M_connect) {
  2550     _done_state = S_ready;
  2552     _done_state = S_read_header;
  2563 reconsider_proxy() {
  2564   _proxy_tunnel_now = 
false;
  2565   _proxy_serves_document = 
false;
  2567   if (!_proxy.empty()) {
  2574       (get_proxy_tunnel() || _want_ssl ||
  2575        _method == HTTPEnum::M_connect || _proxy.get_scheme() == 
"socks");
  2579     _proxy_serves_document = !_proxy_tunnel_now;
  2583   make_request_text();
  2585   if (_proxy_tunnel_now) {
  2588     ostringstream request;
  2590       << 
"CONNECT " << _request.get_url().get_server_and_port()
  2591       << 
" " << _client->get_http_version_string() << 
"\r\n";
  2592     if (_client->get_http_version() >= HTTPEnum::HV_11) {
  2594         << 
"Host: " << _request.get_url().get_server_and_port() << 
"\r\n";
  2596     _proxy_header = request.str();
  2597     make_proxy_request_text();
  2600     _proxy_header = string();
  2601     _proxy_request_text = string();
  2611 reset_for_new_request() {
  2612   if (downloader_cat.is_spam()) {
  2613     downloader_cat.spam()
  2614       << _NOTIFY_HTTP_CHANNEL_ID
  2615       << 
"reset_for_new_request.\n";
  2618   reset_download_to();
  2619   reset_body_stream();
  2621   _last_status_code = 0;
  2622   _status_entry = StatusEntry();
  2624   _response_type = RT_none;
  2625   _redirect_trail.clear();
  2626   _bytes_downloaded = 0;
  2627   _bytes_requested = 0;
  2639 finished_body(
bool has_trailer) {
  2640   if (will_close_connection() && _download_dest == DD_none) {
  2641     if (downloader_cat.is_debug()) {
  2642       downloader_cat.debug()
  2643         << _NOTIFY_HTTP_CHANNEL_ID
  2644         << 
"resetting to finish body; server would close anyway.\n";
  2650       _state = HTTPChannel::S_read_body;
  2652       _state = HTTPChannel::S_read_trailer;
  2666 open_download_file() {
  2667   _subdocument_resumes = (_subdocument_resumes && _first_byte_delivered != 0);
  2669   if (_download_dest == DD_file) {
  2671     _download_to_stream = vfs->
open_write_file(_download_to_filename, 
false, !_subdocument_resumes);
  2672     if (_download_to_stream == 
nullptr) {
  2673       downloader_cat.info()
  2674         << _NOTIFY_HTTP_CHANNEL_ID
  2675         << 
"Could not open " << _download_to_filename << 
" for writing.\n";
  2676       _status_entry._status_code = SC_download_open_error;
  2682   if (_subdocument_resumes) {
  2683     if (_download_dest == DD_file) {
  2687       _download_to_stream->seekp(0, std::ios::end);
  2688       if (_first_byte_delivered > (
size_t)_download_to_stream->tellp()) {
  2689         downloader_cat.info()
  2690           << _NOTIFY_HTTP_CHANNEL_ID
  2691           << 
"Invalid starting position of byte " << _first_byte_delivered
  2692           << 
" within " << _download_to_filename << 
" (which has "  2693           << _download_to_stream->tellp() << 
" bytes)\n";
  2694         close_download_stream();
  2695         _status_entry._status_code = SC_download_invalid_range;
  2700       _download_to_stream->seekp(_first_byte_delivered);
  2702     } 
else if (_download_dest == DD_ram) {
  2703       if (_first_byte_delivered > _download_to_ramfile->_data.length()) {
  2704         downloader_cat.info()
  2705           << _NOTIFY_HTTP_CHANNEL_ID
  2706           << 
"Invalid starting position of byte " << _first_byte_delivered
  2707           << 
" within Ramfile (which has "  2708           << _download_to_ramfile->_data.length() << 
" bytes)\n";
  2709         close_download_stream();
  2710         _status_entry._status_code = SC_download_invalid_range;
  2715       if (_first_byte_delivered == 0) {
  2716         _download_to_ramfile->_data = string();
  2718         _download_to_ramfile->_data =
  2719           _download_to_ramfile->_data.substr(0, _first_byte_delivered);
  2721     } 
else if (_download_dest == DD_stream) {
  2725       _download_to_stream->seekp(0, std::ios::end);
  2726       if (_first_byte_delivered > (
size_t)_download_to_stream->tellp()) {
  2727         downloader_cat.info()
  2728           << _NOTIFY_HTTP_CHANNEL_ID
  2729           << 
"Invalid starting position of byte " << _first_byte_delivered
  2730           << 
" within stream (which has "  2731           << _download_to_stream->tellp() << 
" bytes)\n";
  2732         close_download_stream();
  2733         _status_entry._status_code = SC_download_invalid_range;
  2738       _download_to_stream->seekp(_first_byte_delivered);
  2745     if (_download_dest == DD_file || _download_dest == DD_stream) {
  2746       _download_to_stream->seekp(0);
  2747     } 
else if (_download_dest == DD_ram) {
  2748       _download_to_ramfile->_data = string();
  2762 server_getline(
string &str) {
  2763   nassertr(!_source.is_null(), 
false);
  2764   int ch = (*_source)->get();
  2765   while (ch != EOF && !(*_source)->fail()) {
  2770       _working_get = string();
  2774         size_t p = str.length();
  2775         while (p > 0 && isspace(str[p - 1])) {
  2778         str = str.substr(0, p);
  2780       if (downloader_cat.is_spam()) {
  2781         downloader_cat.spam()
  2782           << _NOTIFY_HTTP_CHANNEL_ID
  2783           << 
"recv: " << str << 
"\n";
  2792       _working_get += (char)ch;
  2794     ch = (*_source)->get();
  2807 server_getline_failsafe(
string &str) {
  2808   if (!server_getline(str)) {
  2809     if (_bio.is_null()) {
  2811       if (_response_type == RT_hangup) {
  2813         _status_entry._status_code = SC_lost_connection;
  2814         _state = S_try_next_proxy;
  2818         _response_type = RT_hangup;
  2825       if (elapsed > get_http_timeout()) {
  2827         downloader_cat.info()
  2828           << _NOTIFY_HTTP_CHANNEL_ID
  2829           << 
"Timeout waiting for "  2830           << _request.get_url().get_server_and_port()
  2831           << 
" in server_getline_failsafe (" << elapsed
  2832           << 
" seconds elapsed).\n";
  2833         _status_entry._status_code = SC_timeout;
  2834         _state = S_try_next_proxy;
  2850 server_get(
string &str, 
size_t num_bytes) {
  2851   nassertr(!_source.is_null(), 
false);
  2852   int ch = (*_source)->get();
  2853   while (ch != EOF && !(*_source)->fail()) {
  2854     _working_get += (char)ch;
  2855     if (_working_get.length() >= num_bytes) {
  2857       _working_get = string();
  2861     ch = (*_source)->get();
  2874 server_get_failsafe(
string &str, 
size_t num_bytes) {
  2875   if (!server_get(str, num_bytes)) {
  2876     if (_bio.is_null()) {
  2878       if (_response_type == RT_hangup) {
  2880         _status_entry._status_code = SC_lost_connection;
  2881         _state = S_try_next_proxy;
  2885         _response_type = RT_hangup;
  2892       if (elapsed > get_http_timeout()) {
  2894         downloader_cat.info()
  2895           << _NOTIFY_HTTP_CHANNEL_ID
  2896           << 
"Timeout waiting for "  2897           << _request.get_url().get_server_and_port()
  2898           << 
" in server_get_failsafe (" << elapsed
  2899           << 
" seconds elapsed).\n";
  2900         _status_entry._status_code = SC_timeout;
  2901         _state = S_try_next_proxy;
  2921 server_send(
const string &str, 
bool secret) {
  2922   nassertr(str.length() > _sent_so_far, 
true);
  2927   size_t bytes_to_send = str.length() - _sent_so_far;
  2929     BIO_write(*_bio, str.data() + _sent_so_far, bytes_to_send);
  2931   if (write_count <= 0) {
  2932     if (BIO_should_retry(*_bio)) {
  2937     if (downloader_cat.is_debug()) {
  2938       downloader_cat.debug()
  2939         << _NOTIFY_HTTP_CHANNEL_ID
  2940         << 
"Lost connection to server unexpectedly during write.\n";
  2946   if (downloader_cat.is_spam()) {
  2947     downloader_cat.spam()
  2948       << _NOTIFY_HTTP_CHANNEL_ID
  2949       << 
"wrote " << write_count << 
" bytes to " << _bio << 
"\n";
  2953   if (!secret && downloader_cat.is_spam()) {
  2954     show_send(str.substr(0, write_count));
  2958   if (write_count < (
int)bytes_to_send) {
  2959     _sent_so_far += write_count;
  2974 parse_http_response(
const string &line) {
  2976   if (line.length() < 5 || line.substr(0, 5) != string(
"HTTP/")) {
  2978     _status_entry._status_code = SC_non_http_response;
  2979     if (_response_type == RT_non_http) {
  2981       _state = S_try_next_proxy;
  2986       if (downloader_cat.is_debug()) {
  2987         downloader_cat.debug()
  2988           << _NOTIFY_HTTP_CHANNEL_ID
  2989           << 
"got non-HTTP response, resetting.\n";
  2992       _response_type = RT_non_http;
  2999   while (p < line.length() && !isspace(line[p])) {
  3002   _http_version_string = line.substr(0, p);
  3003   _http_version = HTTPClient::parse_http_version_string(_http_version_string);
  3005   while (p < line.length() && isspace(line[p])) {
  3009   while (q < line.length() && !isspace(line[q])) {
  3012   string status_code = line.substr(p, q - p);
  3013   _status_entry._status_code = atoi(status_code.c_str());
  3015   while (q < line.length() && isspace(line[q])) {
  3018   _status_entry._status_string = line.substr(q, line.length() - q);
  3028 parse_http_header() {
  3030   if (!server_getline(line)) {
  3034   while (!line.empty()) {
  3035     if (isspace(line[0])) {
  3038       while (p < line.length() && isspace(line[p])) {
  3041       _current_field_value += line.substr(p - 1);
  3045       if (!_current_field_name.empty()) {
  3046         store_header_field(_current_field_name, _current_field_value);
  3047         _current_field_value = string();
  3050       size_t colon = line.find(
':');
  3051       if (colon != string::npos) {
  3052         _current_field_name = 
downcase(line.substr(0, colon));
  3053         size_t p = colon + 1;
  3054         while (p < line.length() && isspace(line[p])) {
  3057         _current_field_value = line.substr(p);
  3061     if (!server_getline(line)) {
  3067   if (!_current_field_name.empty()) {
  3068     store_header_field(_current_field_name, _current_field_value);
  3069     _current_field_value = string();
  3081 parse_content_range(
const string &content_range) {
  3084   while (p < content_range.length() && !isspace(content_range[p])) {
  3088   string units = content_range.substr(0, p);
  3089   while (p < content_range.length() && isspace(content_range[p])) {
  3093   if (units == 
"bytes") {
  3094     const char *c_str = content_range.c_str();
  3096     if (p < content_range.length() && isdigit(content_range[p])) {
  3097       long first_byte = strtol(c_str + p, &endptr, 10);
  3099       if (p < content_range.length() && content_range[p] == 
'-') {
  3101         if (p < content_range.length() && isdigit(content_range[p])) {
  3102           long last_byte = strtol(c_str + p, &endptr, 10);
  3105           if (last_byte >= first_byte) {
  3106             _first_byte_delivered = first_byte;
  3107             _last_byte_delivered = last_byte;
  3126   nassertv(!_source.is_null());
  3127   if ((*_source)->is_closed()) {
  3128     if (downloader_cat.is_debug()) {
  3129       downloader_cat.debug()
  3130         << _NOTIFY_HTTP_CHANNEL_ID
  3131         << 
"Lost connection to server unexpectedly during read.\n";
  3328 check_preapproved_server_certificate(X509 *cert, 
bool &cert_preapproved,
  3329                                      bool &cert_name_preapproved)
 const {
  3330   return _client->check_preapproved_server_certificate(_request.get_url(),
  3331                                                        cert, cert_preapproved,
  3332                                                        cert_name_preapproved);
  3340 validate_server_name(X509 *cert) {
  3341   string hostname = _request.get_url().get_server();
  3343   vector_string cert_names;
  3347   STACK_OF(GENERAL_NAME) *subject_alt_names =
  3348     (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i(cert, NID_subject_alt_name, 
nullptr, 
nullptr);
  3349   if (subject_alt_names != 
nullptr) {
  3350     int num_alts = sk_GENERAL_NAME_num(subject_alt_names);
  3351     for (
int i = 0; i < num_alts; ++i) {
  3353       const GENERAL_NAME *alt_name =
  3354         sk_GENERAL_NAME_value(subject_alt_names, i);
  3356       if (alt_name->type == GEN_DNS) {
  3357         char *buffer = 
nullptr;
  3358         int len = ASN1_STRING_to_UTF8((
unsigned char**)&buffer,
  3361           cert_names.push_back(
string(buffer, len));
  3363         if (buffer != 
nullptr) {
  3364           OPENSSL_free(buffer);
  3370   if (cert_names.empty()) {
  3373     X509_NAME *xname = X509_get_subject_name(cert);
  3374     if (xname != 
nullptr) {
  3375       string common_name = get_x509_name_component(xname, NID_commonName);
  3376       cert_names.push_back(common_name);
  3380   if (cert_names.empty()) {
  3381     downloader_cat.info()
  3382       << _NOTIFY_HTTP_CHANNEL_ID
  3383       << 
"Server certificate from " << hostname
  3384       << 
" provides no name.\n";
  3388   if (downloader_cat.is_debug()) {
  3389     downloader_cat.debug()
  3390       << _NOTIFY_HTTP_CHANNEL_ID
  3391       << 
"Server certificate from " << hostname
  3392       << 
" provides name(s):";
  3393     vector_string::const_iterator si;
  3394     for (si = cert_names.begin(); si != cert_names.end(); ++si) {
  3395       const string &cert_name = (*si);
  3396       downloader_cat.debug(
false)
  3397         << 
" " << cert_name;
  3399     downloader_cat.debug(
false)
  3405   vector_string::const_iterator si;
  3406   for (si = cert_names.begin(); si != cert_names.end(); ++si) {
  3407     const string &cert_name = (*si);
  3409     if (match_cert_name(cert_name, hostname)) {
  3414   downloader_cat.info()
  3415     << _NOTIFY_HTTP_CHANNEL_ID
  3416     << 
"Server certificate from " << hostname
  3417     << 
" provides wrong name(s):";
  3418   for (si = cert_names.begin(); si != cert_names.end(); ++si) {
  3419     const string &cert_name = (*si);
  3420     downloader_cat.info(
false)
  3421       << 
" " << cert_name;
  3423   downloader_cat.info(
false)
  3434 match_cert_name(
const string &cert_name, 
const string &hostname) {
  3440   pattern.set_case_sensitive(
false);
  3441   pattern.set_nomatch_chars(
".");
  3442   return pattern.matches(hostname);
  3449 string HTTPChannel::
  3450 get_x509_name_component(X509_NAME *name, 
int nid) {
  3451   ASN1_OBJECT *obj = OBJ_nid2obj(nid);
  3453   if (obj == 
nullptr) {
  3458   int i = X509_NAME_get_index_by_OBJ(name, obj, -1);
  3463   ASN1_STRING *data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
  3464   return string((
char *)data->data, data->length);
  3474   _proxy_auth = _client->select_auth(_proxy, 
true, _proxy_realm);
  3475   _proxy_username = string();
  3476   if (_proxy_auth != 
nullptr) {
  3477     _proxy_realm = _proxy_auth->get_realm();
  3478     _proxy_username = _client->select_username(_proxy, 
true, _proxy_realm);
  3481   if (_method == HTTPEnum::M_connect) {
  3489   _www_auth = _client->select_auth(_request.get_url(), 
false, _www_realm);
  3490   _www_username = string();
  3491   if (_www_auth != 
nullptr) {
  3492     _www_realm = _www_auth->get_realm();
  3493     _www_username = _client->select_username(_request.get_url(), 
false, _www_realm);
  3496   string request_path;
  3497   if (_proxy_serves_document) {
  3502     request_path = url_no_username.
get_url();
  3507     request_path = _request.get_url().get_path_and_query();
  3512   if (request_path.empty()) {
  3516   ostringstream stream;
  3519     << _method << 
" " << request_path << 
" "  3520     << _client->get_http_version_string() << 
"\r\n";
  3522   if (_client->get_http_version() >= HTTPEnum::HV_11) {
  3524     if (_request.get_url().has_port() && _request.get_url().is_default_port()) {
  3529       string server = _request.get_url().get_server();
  3530       if (server.find(
':') != string::npos) {
  3531         stream << 
"Host: [" << server << 
"]";
  3533         stream << 
"Host: " << server;
  3536       stream << 
"Host: " << _request.get_url().get_server_and_port();
  3539     if (!get_persistent_connection()) {
  3541         << 
"Connection: close\r\n";
  3545   if (_last_byte_requested != 0) {
  3547       << 
"Range: bytes=" << _first_byte_requested << 
"-"  3548       << _last_byte_requested << 
"\r\n";
  3550   } 
else if (_first_byte_requested != 0) {
  3552       << 
"Range: bytes=" << _first_byte_requested << 
"-\r\n";
  3555   switch (_request.get_request_mode()) {
  3556   case DocumentSpec::RM_any:
  3558     if (_first_byte_requested != 0) {
  3562       if (_request.has_tag()) {
  3564           << 
"If-Range: " << _request.get_tag().get_string() << 
"\r\n";
  3565       } 
else if (_request.has_date()) {
  3567           << 
"If-Range: " << _request.get_date().get_string() << 
"\r\n";
  3572   case DocumentSpec::RM_equal:
  3574     if (_request.has_tag()) {
  3576         << 
"If-Match: " << _request.get_tag().get_string() << 
"\r\n";
  3578     if (_request.has_date()) {
  3580         << 
"If-Unmodified-Since: " << _request.get_date().get_string()
  3585   case DocumentSpec::RM_newer:
  3587     if (_request.has_tag()) {
  3589         << 
"If-None-Match: " << _request.get_tag().get_string() << 
"\r\n";
  3591     if (_request.has_date()) {
  3593         << 
"If-Modified-Since: " << _request.get_date().get_string()
  3598   case DocumentSpec::RM_equal_or_newer:
  3600     if (_request.has_date()) {
  3605         << 
"If-Modified-Since: " << (_request.get_date() - 1).get_string()
  3611   switch (_request.get_cache_control()) {
  3612   case DocumentSpec::CC_allow_cache:
  3616   case DocumentSpec::CC_revalidate:
  3619       << 
"Cache-Control: max-age=0\r\n";
  3622   case DocumentSpec::CC_no_cache:
  3625       << 
"Cache-Control: no-cache\r\n"  3626       << 
"Pragma: no-cache\r\n";
  3630   _client->send_cookies(stream, _request.get_url());
  3632   if (!_body.empty()) {
  3634       << 
"Content-Type: " << _content_type << 
"\r\n"  3635       << 
"Content-Length: " << _body.length() << 
"\r\n";
  3638   _header = stream.str();
  3648 make_proxy_request_text() {
  3649   _proxy_request_text = _proxy_header;
  3651   if (_proxy_auth != 
nullptr && !_proxy_username.empty()) {
  3652     _proxy_request_text += 
"Proxy-Authorization: ";
  3653     _proxy_request_text +=
  3654       _proxy_auth->generate(HTTPEnum::M_connect, _request.get_url().get_server_and_port(),
  3655                             _proxy_username, _body);
  3656     _proxy_request_text += 
"\r\n";
  3659   _proxy_request_text += 
"\r\n";
  3667 make_request_text() {
  3668   _request_text = _header;
  3670   if (_proxy_serves_document &&
  3671       _proxy_auth != 
nullptr && !_proxy_username.empty()) {
  3672     _request_text += 
"Proxy-Authorization: ";
  3674       _proxy_auth->generate(_method, _request.get_url().get_url(), _proxy_username, _body);
  3675     _request_text += 
"\r\n";
  3678   if (_www_auth != 
nullptr && !_www_username.empty()) {
  3679     string authorization =
  3680     _request_text += 
"Authorization: ";
  3682       _www_auth->generate(_method, _request.get_url().get_path_and_query(), _www_username, _body);
  3683     _request_text += 
"\r\n";
  3686   _request_text += _send_extra_headers;
  3687   _request_text += 
"\r\n";
  3688   _request_text += _body;
  3704     if (downloader_cat.is_debug()) {
  3705       downloader_cat.debug()
  3706         << _NOTIFY_HTTP_CHANNEL_ID
  3707         << 
"resetting for new server "  3719 store_header_field(
const string &field_name, 
const string &field_value) {
  3720   std::pair<Headers::iterator, bool> insert_result =
  3721     _headers.insert(Headers::value_type(field_name, field_value));
  3723   if (!insert_result.second) {
  3726     Headers::iterator hi = insert_result.first;
  3727     (*hi).second += 
", ";
  3728     (*hi).second += field_value;
  3731   if (field_name == 
"set-cookie") {
  3732     _client->set_cookie(HTTPCookie(field_value, _request.get_url()));
  3741 show_send(
const string &message) {
  3743   size_t newline = message.find(
'\n', start);
  3744   while (newline != string::npos) {
  3746     downloader_cat.spam()
  3747       << 
"send: " << message.substr(start, newline - start - 1) << 
"\n";
  3748     start = newline + 1;
  3749     newline = message.find(
'\n', start);
  3752   if (start < message.length()) {
  3753     downloader_cat.spam()
  3754       << 
"send: " << message.substr(start) << 
" (no newline)\n";
  3764 reset_download_to() {
  3765   _started_download = 
false;
  3766   close_download_stream();
  3767   _download_dest = DD_none;
  3775 close_download_stream() {
  3776   if (_download_to_stream != 
nullptr) {
  3777     _download_to_stream->flush();
  3778     if (_download_dest == DD_file) {
  3782   _download_to_ramfile = 
nullptr;
  3783   _download_to_stream = 
nullptr;
  3792   if (downloader_cat.is_spam()) {
  3793     downloader_cat.spam()
  3794       << _NOTIFY_HTTP_CHANNEL_ID
  3795       << 
"reset_to_new.\n";
  3806 reset_body_stream() {
  3807   if (_owns_body_stream) {
  3808     if (_body_stream != 
nullptr) {
  3809       close_read_body(_body_stream);
  3810       nassertv(_body_stream == 
nullptr && !_owns_body_stream);
  3813     _body_stream = 
nullptr;
  3822 close_connection() {
  3823   reset_body_stream();
  3826   _working_get = string();
  3837 more_useful_status_code(
int a, 
int b) {
  3838   if (a >= 100 && b >= 100) {
  3851     int series_a = (a / 100);
  3852     int series_b = (b / 100);
  3855     return (series_a < series_b);
  3858   if (a < 100 && b < 100) {
  3866     return (a > SC_http_error_watermark);
  3870   return (b < SC_http_error_watermark);
  3878 operator << (ostream &out, HTTPChannel::State state) {
  3880   return out << (int)state;
  3883   case HTTPChannel::S_new:
  3884     return out << 
"new";
  3886   case HTTPChannel::S_try_next_proxy:
  3887     return out << 
"try_next_proxy";
  3889   case HTTPChannel::S_connecting:
  3890     return out << 
"connecting";
  3892   case HTTPChannel::S_connecting_wait:
  3893     return out << 
"connecting_wait";
  3895   case HTTPChannel::S_http_proxy_ready:
  3896     return out << 
"http_proxy_ready";
  3898   case HTTPChannel::S_http_proxy_request_sent:
  3899     return out << 
"http_proxy_request_sent";
  3901   case HTTPChannel::S_http_proxy_reading_header:
  3902     return out << 
"http_proxy_reading_header";
  3904   case HTTPChannel::S_socks_proxy_greet:
  3905     return out << 
"socks_proxy_greet";
  3907   case HTTPChannel::S_socks_proxy_greet_reply:
  3908     return out << 
"socks_proxy_greet_reply";
  3910   case HTTPChannel::S_socks_proxy_connect:
  3911     return out << 
"socks_proxy_connect";
  3913   case HTTPChannel::S_socks_proxy_connect_reply:
  3914     return out << 
"socks_proxy_connect_reply";
  3916   case HTTPChannel::S_setup_ssl:
  3917     return out << 
"setup_ssl";
  3919   case HTTPChannel::S_ssl_handshake:
  3920     return out << 
"ssl_handshake";
  3922   case HTTPChannel::S_ready:
  3923     return out << 
"ready";
  3925   case HTTPChannel::S_request_sent:
  3926     return out << 
"request_sent";
  3928   case HTTPChannel::S_reading_header:
  3929     return out << 
"reading_header";
  3931   case HTTPChannel::S_start_direct_file_read:
  3932     return out << 
"start_direct_file_read";
  3934   case HTTPChannel::S_read_header:
  3935     return out << 
"read_header";
  3937   case HTTPChannel::S_begin_body:
  3938     return out << 
"begin_body";
  3940   case HTTPChannel::S_reading_body:
  3941     return out << 
"reading_body";
  3943   case HTTPChannel::S_read_body:
  3944     return out << 
"read_body";
  3946   case HTTPChannel::S_read_trailer:
  3947     return out << 
"read_trailer";
  3949   case HTTPChannel::S_failure:
  3950     return out << 
"failure";
  3953   return out << 
"invalid state(" << (int)state << 
")";
  3957 #endif  // HAVE_OPENSSL PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static TrueClock * get_global_ptr()
Returns a pointer to the one TrueClock object in the world.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A container for a URL, e.g.
A hierarchy of directories and files that appears to be one continuous file system,...
A container for an "entity tag" from an HTTP server.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_binary()
Indicates that the filename represents a binary file.
string downcase(const string &s)
Returns the input string with all uppercase letters converted to lowercase.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is a convenience class to specialize ConfigVariable as a floating- point type.
get_scheme
Returns the scheme specified by the URL, or empty string if no scheme is specified.
The name of a file, such as a texture file or an Egg file.
An in-memory buffer specifically designed for downloading files to memory.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
get_path
Returns the path specified by the URL, or "/" if no path is specified.
A container for an HTTP-legal time/date indication.
get_authority
Returns the authority specified by the URL (this includes username, server, and/or port),...
bool is_local() const
Returns true if the filename is local, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
set_username
Replaces the username part of the URL specification.
get_port
Returns the port number specified by the URL, or the default port if not specified.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream * open_write_file(const Filename &filename, bool auto_wrap, bool truncate)
Convenience function; returns a newly allocated ostream if the file exists and can be written,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const std::string & get_url() const
Returns the complete URL specification.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_server
Returns the server name specified by the URL, if any.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A descriptor that refers to a particular version of a document.
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_server_and_port
Returns a string consisting of the server name, followed by a colon, followed by the port number.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class can be used to test for string matches against standard Unix- shell filename globbing conv...