diff --git a/panda/src/downloader/downloader.cxx b/panda/src/downloader/downloader.cxx index dd131dd4a2..e2c9850c77 100644 --- a/panda/src/downloader/downloader.cxx +++ b/panda/src/downloader/downloader.cxx @@ -85,6 +85,74 @@ Downloader:: cleanup(); } +//////////////////////////////////////////////////////////////////// +// Function: Downloader::connect_to_server_by_proxy +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +int Downloader:: +connect_to_server_by_proxy(const string &proxy_name, uint proxy_port, + const string &server_name, uint server_port) { + if (connect_to_server(proxy_name, proxy_port) != EU_success) + downloader_cat.error() + << "Downloader::connect_to_server_by_proxy() - could not connect to: " + << proxy_name << endl; + return EU_error_abort; + + // Send an HTTP request asking the proxy to connect to the server + string request = "CONNECT "; + request += server_name; + request += ":"; + stringstream port_stream; + port_stream << server_port; + request += port_stream.str(); + request += " HTTP/1.1\012\012"; + int outlen = request.size(); + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::proxy() - Sending request:\n" << request << endl; + int send_ret = safe_send(_socket, request.c_str(), outlen, + (long)downloader_timeout); + if (send_ret < 0) + return send_ret; + + uint fret; + + _current_status = new DownloadStatus(_buffer->_buffer, 0, 0, 0, false); + for (int i = 0; i <= 100; i++) { + fret = fast_receive(_socket, _current_status, MAX_RECEIVE_BYTES); + if (fret == EU_eof || fret < 0) { + break; + } else if (fret == EU_success) { + _got_any_data = true; + } + } + + if (fret == EU_eof) { + if (_got_any_data == true) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::proxy() - Got eof" << endl; + // parse proxy message here + uint ret = parse_proxy_response(_current_status); + cleanup(); + return ret; + } else { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::proxy() - Got 0 bytes" << endl; + return EU_error_abort; + } + } else if (fret == EU_network_no_data) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::proxy() - No data" << endl; + return EU_error_abort; + } else if (fret < 0) { + return fret; + } +} + //////////////////////////////////////////////////////////////////// // Function: Downloader::connect_to_server // Access: Public @@ -763,6 +831,81 @@ parse_http_response(const string &resp) { return EU_error_abort; } +//////////////////////////////////////////////////////////////////// +// Function: Downloader::parse_proxy_response +// Access: Private +// Description: Looks for a valid proxy response. +// Function returns false +// on an error condition, otherwise true. +//////////////////////////////////////////////////////////////////// +int Downloader:: +parse_proxy_response(DownloadStatus *status) { + nassertr(status != NULL, EU_error_abort); + + if (status->_bytes_in_buffer == 0) { + downloader_cat.error() + << "Downloader::parse_proxy_response() - Empty buffer!" << endl; + return EU_error_abort; + } + + string bufstr((char *)status->_start, status->_bytes_in_buffer); + size_t p = 0; + while (p < bufstr.length()) { + // Server sends out CR LF (\r\n) as newline delimiter + size_t nl = bufstr.find("\015\012", p); + if (nl == string::npos) { + downloader_cat.error() + << "Downloader::parse_proxy_response() - No newlines in buffer of " + << "length: " << status->_bytes_in_buffer << endl; + return EU_error_abort; + } else if (p == 0 && nl == p) { + downloader_cat.error() + << "Downloader::parse_proxy_response() - Buffer begins with newline!" + << endl; + return EU_error_abort; + } + + string component = bufstr.substr(p, nl - p); + + // The first line of the response should say whether + // got an error or not + if (status->_first_line_complete == false) { + status->_first_line_complete = true; + int parse_ret = parse_http_response(component); + if (parse_ret == EU_success) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::parse_proxy_response() - valid proxy: " + << component << endl; + } else { + return parse_ret; + } + } + + // Look for proxy agent + size_t cpos = component.find(":"); + string tline = component.substr(0, cpos); + if (tline == "Proxy-agent") { + if (downloader_cat.debug()) + downloader_cat.debug() + << "Downloader::parse_proxy_response() - proxy agent: %s" + << component << endl; + } + + // Two consecutive (CR LF)s indicates end of HTTP response + if (nl == p) { + if (downloader_cat.is_debug()) + downloader_cat.debug() + << "Downloader::parse_proxy_response() - complete" << endl; + return EU_success; + } + + p = nl + 2; + } + + return EU_error_abort; +} + //////////////////////////////////////////////////////////////////// // Function: Downloader::parse_header // Access: Private diff --git a/panda/src/downloader/downloader.h b/panda/src/downloader/downloader.h index 5b104542a2..fce00a737e 100644 --- a/panda/src/downloader/downloader.h +++ b/panda/src/downloader/downloader.h @@ -46,6 +46,8 @@ PUBLISHED: Downloader(void); virtual ~Downloader(void); + int connect_to_server_by_proxy(const string &proxy_name, uint proxy_port, + const string &server_name, uint server_port=80); int connect_to_server(const string &name, uint port=80); void disconnect_from_server(void); @@ -98,6 +100,7 @@ private: int fast_receive(int socket, DownloadStatus *status, int rec_size); int parse_http_response(const string &resp); int parse_header(DownloadStatus *status); + int parse_proxy_response(DownloadStatus *status); int write_to_disk(DownloadStatus *status); int run_to_ram(void); int write_to_ram(DownloadStatus *status);