I'm trying to implement a very simple proxy server with the following code. You set your browser's proxy to 192.168.1.x:8080 and web pages are accessible through the proxy.
#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
#include <boost/algorithm/string.hpp>
#include <curl/curl.h>
#include <cstdlib>
using boost::asio::ip::tcp;
int port=8080;
//CURL *curl;
//CURLcode res;
static size_t write_to_string(void *ptr, size_t size, size_t count, void *stream) {
((std::string*)stream)->append((char*)ptr, 0, size*count);
return size*count;
}
class session{
public:
session(boost::asio::io_service& io_service):socket_(io_service){
}
tcp::socket &socket(){
return socket_;
}
void start(){
socket_.async_read_some(boost::asio::buffer(data_,max_length),boost::bind(&session::handle_read,this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
}
private:
void handle_read(const boost::system::error_code& error,size_t bytes_transferred){
CURL *curl;
CURLcode res;
std::string response;
std::string errorBuffer[CURL_ERROR_SIZE];
std::string host="";
std::string url="";
if(!error){
//boost::asio::async_write(socket_,boost::asio::buffer(data_,bytes_transferred),boost::bind(&session::handle_write,this,boost::asio::placeholders::error));
printf("%s",data_);
//parse data_:
//std::string host="";
//std::string url="";
std::vector<std::string> split1;
boost::split(split1, data_, boost::is_any_of("\r\n"));
std::vector<std::string> split2;
boost::split(split2,split1.at(0),boost::is_any_of(" "));
std::cout<<"***"<<split2.at(0)<<"***"<<std::endl;
if(split2.at(0).compare("GET")==0){
printf("Get request recieved\n");
url=split2.at(1);
int i=0;
for(i=1;i<split1.size();i++){
if(split1.at(i).compare("Host:")>0){
std::cout<<split1.at(i)<<std::endl;
std::vector<std::string> split3;
boost::split(split3,split1.at(i),boost::is_any_of(" "));
std::cout<<split3.at(1)<<std::endl;
host=split3.at(1);
break;
}
}
}
//trim host to remove \r\n
host.erase(host.find_last_not_of(" \n\r\t")+1);
url.erase(url.find_last_not_of(" \n\r\t")+1);
//std::string response;
//std::string errorBuffer[CURL_ERROR_SIZE];
//CURL *curl;
//CURLcode res;
curl=curl_easy_init();
if(curl){
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 0);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(curl, CURLOPT_ENCODING, "gzip");
//curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookies.txt");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_to_string);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
std::cout<<errorBuffer<<std::endl;
//curl_easy_setopt(curl,CURLOPT_URL,url.c_str());
//curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,write_to_string);
//curl_easy_setopt(curl,CURLOPT_WRITEDATA,&response);
res=curl_easy_perform(curl);
std::cout<<">>>"<<res<<std::endl;
curl_easy_cleanup(curl);
std::cout<<response<<std::endl;
boost::asio::async_write(socket_,boost::asio::buffer(response,response.length()),boost::bind(&session::handle_write,this,boost::asio::placeholders::error));
//curl_free(curl);
}else{
printf("Error: curl can't be init'd");
}
}else{
printf("***handle_read: Error***\n");
std::cout<<error<<std::endl;
std::cout<<"EOH:"<<res<<std::endl;
std::cout<<url<<std::endl;
std::cout<<"EOH:"<<errorBuffer<<std::endl;
delete this;
}
}
void handle_write(const boost::system::error_code& error){
if (!error){
socket_.async_read_some(boost::asio::buffer(data_, max_length),boost::bind(&session::handle_read, this,boost::asio::placeholders::error,boost::asio::placeholders::bytes_transferred));
socket_.cancel();
}else{
printf("***handle_write: Error***");
std::cout<<error<<std::endl;
delete this;
}
}
tcp::socket socket_;
enum { max_length = 1000000 };
char data_[max_length];
};
class server
{
public:
server(boost::asio::io_service& io_service, short port): io_service_(io_service),acceptor_(io_service,tcp::endpoint(tcp::v4(), port)){
start_accept();
}
private:
void start_accept(){
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(),boost::bind(&server::handle_accept, this, new_session,boost::asio::placeholders::error));
}
void handle_accept(session* new_session,const boost::system::error_code& error){
if (!error){
new_session->start();
}else{
delete new_session;
}
start_accept();
}
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
int main(){
try{
boost::asio::io_service io_service;
//tcp_server write(io_service);
server read(io_service,port);
io_service.run();
}
catch (std::exception& e){
std::cerr << e.what() << std::endl;
}
return 0;
}
Compile using g++ proxy.c -lboost_system -lcurl
The trouble I'm having is that images won't download! All other texty files (html, js, css) download fine, it's just images won't appear.
Can anyone give me any suggestions? I'm really stuck now. I was thinking about switching curl into some sort of "binary mode". When I cout the string that contains the image, it seems to print to sdtout fine (I can see the "PNG" header). But when I try to write this file to the socket, it's not coming up in the browser for some reason I cannot get to the bottom of.
On recommendation of @Tomalak Geret'kal, I'm now using curlpp
curlpp::Cleanup myCleanup;
curlpp::Easy myRequest;
myRequest.setOpt<cURLpp::Options::Url>(url);
std::ostringstream os;
curlpp::options::WriteStream ws(&os);
myRequest.setOpt(ws);
myRequest.perform();
os << myRequest;
boost::asio::async_write(socket_,boost::asio::buffer(xxx,xxx.length())),boost::bind(&session::handle_write,this,boost::asio::placeholders::error));
My question now is, how do I write using async_write? I'm not sure what to convert os
to in order for it to be compatible with async_write...