00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #include <sstream>
00034
00035 #include "asio_proxy_connection.hpp"
00036
00037 proxy_connection::proxy_connection(tcp::socket& socket,
00038 proxy_information pi,
00039 ana::address address,
00040 ana::port port,
00041 ana::timer* timer) :
00042 socket_(socket),
00043 proxy_info_(pi),
00044 address_(address),
00045 port_(port),
00046 manager_( NULL ),
00047 conn_handler_( NULL ),
00048 authenticating_( false ),
00049 timer_( timer )
00050 {
00051 }
00052
00053
00054 std::string* proxy_connection::generate_connect_request() const
00055 {
00056 return new std::string
00057 (
00058 "CONNECT " + address_ + ":" + port_ + " HTTP/1.0\n"
00059 "User-agent: ana 0.1 \n"
00060 "\n"
00061 );
00062 }
00063
00064 std::string* proxy_connection::generate_base64_credentials() const
00065 {
00066 const std::string user_and_pass( proxy_info_.user_name + ':' + proxy_info_.password );
00067 return new std::string
00068 (
00069 "CONNECT " + address_ + ":" + port_ + " HTTP/1.0\n"
00070 "User-agent: ana 0.1 \n"
00071 "Proxy-Connection: keep-alive\n"
00072 "Proxy-Authorization: Basic " + base64_encode(user_and_pass.c_str(),
00073 user_and_pass.size() ) + "\n"
00074 "\n"
00075 );
00076 }
00077
00078 std::string proxy_connection::base64_encode(char const* bytes_to_encode, unsigned int in_len) const
00079 {
00080 std::string ret;
00081 int i = 0;
00082 int j = 0;
00083 unsigned char char_array_3[3];
00084 unsigned char char_array_4[4];
00085 const char base64_chars[(1 << 6) + 2]
00086 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
00087
00088 while (in_len--) {
00089 char_array_3[i++] = *(bytes_to_encode++);
00090 if (i == 3) {
00091 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
00092 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
00093 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
00094 char_array_4[3] = char_array_3[2] & 0x3f;
00095
00096 for(i = 0; (i <4) ; i++)
00097 ret += base64_chars[char_array_4[i]];
00098 i = 0;
00099 }
00100 }
00101
00102 if (i)
00103 {
00104 for(j = i; j < 3; j++)
00105 char_array_3[j] = '\0';
00106
00107 char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
00108 char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
00109 char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
00110 char_array_4[3] = char_array_3[2] & 0x3f;
00111
00112 for (j = 0; (j < i + 1); j++)
00113 ret += base64_chars[char_array_4[j]];
00114
00115 while((i++ < 3))
00116 ret += '=';
00117
00118 }
00119
00120 return ret;
00121 }
00122
00123 bool proxy_connection::finds( const std::string& source, char const* pattern )
00124 {
00125 const size_t find_pos = source.find( std::string( pattern ) );
00126
00127 return find_pos < source.size();
00128 }
00129
00130 void proxy_connection::handle_response(boost::asio::streambuf* buf,
00131 const boost::system::error_code& ec,
00132 size_t )
00133 {
00134 std::stringstream ss;
00135 ss << buf;
00136 delete buf;
00137
00138 if ( ec )
00139 manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00140 else
00141 {
00142 if ( finds( ss.str(), "200" ) )
00143 manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00144 else
00145 {
00146 if ( ( ! authenticating_ ) && finds( ss.str(), "407" ) )
00147 {
00148 if ( finds( ss.str(), "Proxy-Authenticate: Basic" ) )
00149 {
00150 authenticating_ = true;
00151 socket_.close();
00152
00153 do_connect( );
00154 }
00155 else
00156 manager_->handle_proxy_connection( ana::generic_error, conn_handler_, timer_);
00157
00158 }
00159 else
00160 manager_->handle_proxy_connection( ana::generic_error, conn_handler_, timer_);
00161 }
00162 }
00163 }
00164
00165 void proxy_connection::handle_sent_request(const boost::system::error_code& ,
00166 std::string* request)
00167 {
00168 delete request;
00169
00170 boost::asio::streambuf* buf = new boost::asio::streambuf( );
00171
00172 boost::asio::async_read_until(socket_, *buf,
00173 "\r\n\r\n",
00174 boost::bind(&proxy_connection::handle_response, this,
00175 buf, boost::asio::placeholders::error,_2));
00176 }
00177
00178 void proxy_connection::handle_connect(const boost::system::error_code& ec,
00179 tcp::resolver::iterator endpoint_iterator)
00180 {
00181 if ( ! ec )
00182 {
00183 std::string* request( NULL );
00184
00185 if ( authenticating_ )
00186 request = generate_base64_credentials();
00187 else
00188 request = generate_connect_request();
00189
00190 socket_.async_send(boost::asio::buffer( *request ),
00191 boost::bind(&proxy_connection::handle_sent_request,this,
00192 boost::asio::placeholders::error,
00193 request));
00194 }
00195 else
00196 {
00197 if ( endpoint_iterator == tcp::resolver::iterator() )
00198 manager_->handle_proxy_connection( ec, conn_handler_, timer_ );
00199 else
00200 {
00201
00202 socket_.close();
00203
00204 tcp::endpoint endpoint = *endpoint_iterator;
00205 socket_.async_connect(endpoint,
00206 boost::bind(&proxy_connection::handle_connect, this,
00207 boost::asio::placeholders::error, ++endpoint_iterator));
00208 }
00209 }
00210 }
00211
00212 void proxy_connection::do_connect()
00213 {
00214 try
00215 {
00216 tcp::resolver resolver( socket_.get_io_service() );
00217 tcp::resolver::query query(proxy_info_.proxy_address.c_str(),
00218 proxy_info_.proxy_port.c_str() );
00219 tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
00220
00221 tcp::endpoint endpoint = *endpoint_iterator;
00222
00223 socket_.async_connect(endpoint,
00224 boost::bind(&proxy_connection::handle_connect, this,
00225 boost::asio::placeholders::error, ++endpoint_iterator));
00226 }
00227 catch (const std::exception&)
00228 {
00229 manager_->handle_proxy_connection(ana::generic_error, conn_handler_, timer_ );
00230 }
00231 }
00232
00233 void proxy_connection::connect( proxy_connection_manager* manager,
00234 ana::connection_handler* handler )
00235 {
00236 manager_ = manager;
00237 conn_handler_ = handler;
00238 authenticating_ = false;
00239
00240 do_connect();
00241 }