00001 #include "ug_http_client.h"
00002 #include "moses/Util.h"
00003 #include <iostream>
00004
00005 namespace Moses
00006 {
00007 using boost::asio::ip::tcp;
00008
00009 std::string http_client::content() const { return m_content.str(); }
00010
00011 http_client::
00012 http_client(boost::asio::io_service& io_service,
00013 std::string const& server,
00014 std::string const& port,
00015 std::string const& path)
00016 : resolver_(io_service), socket_(io_service)
00017 {
00018 init(server, port, path);
00019 }
00020
00021 http_client::
00022 http_client(boost::asio::io_service& io_service, std::string url, std::ostream* log)
00023 : resolver_(io_service), socket_(io_service)
00024 {
00025 std::string server;
00026 std::string path = "/";
00027 std::string port = "http";
00028 size_t p = url.find("://"), q;
00029 if (p < url.size())
00030 {
00031 port = url.substr(0,p);
00032 url.erase(0, p+3);
00033 }
00034 p = std::min(url.find_first_of(":/"), url.size());
00035 q = std::min(url.find("/"), url.size());
00036 if (p < url.size() && url[p] == ':')
00037 port = url.substr(p+1,q-p-1);
00038 server = url.substr(0,p);
00039 if (q < url.size())
00040 path = url.substr(q);
00041 #if 1
00042 if (log)
00043 {
00044 *log << HERE << std::endl;
00045
00046 *log << "SERVER " << server << std::endl;
00047 *log << "PORT " << port << "" << std::endl;
00048 *log << "PATH " << path << std::endl;
00049 }
00050 #endif
00051 init(server, port, path);
00052 }
00053
00054 void
00055 http_client::
00056 init(std::string const& server, std::string const& port, std::string const& path)
00057 {
00058
00059
00060
00061
00062
00063 std::ostream request_stream(&request_);
00064 request_stream << "GET " << path << " HTTP/1.0\r\n";
00065 request_stream << "Host: " << server << "\r\n";
00066 request_stream << "Accept: */*\r\n";
00067 request_stream << "Connection: close\r\n\r\n";
00068
00069
00070
00071 tcp::resolver::query query(server, port.c_str());
00072 resolver_.async_resolve(query,
00073 boost::bind(&http_client::handle_resolve, this,
00074 boost::asio::placeholders::error,
00075 boost::asio::placeholders::iterator));
00076
00077 }
00078
00079 void
00080 http_client::
00081 handle_resolve(const boost::system::error_code& err,
00082 tcp::resolver::iterator endpoint_iterator)
00083 {
00084 if (!err)
00085 {
00086
00087
00088 tcp::endpoint endpoint = *endpoint_iterator;
00089 socket_.async_connect(endpoint,
00090 boost::bind(&http_client::handle_connect, this,
00091 boost::asio::placeholders::error, ++endpoint_iterator));
00092 }
00093 else
00094 {
00095 m_error << "Error: " << err.message() << "\n";
00096 }
00097 }
00098
00099 void
00100 http_client::
00101 handle_connect(const boost::system::error_code& err,
00102 tcp::resolver::iterator endpoint_iterator)
00103 {
00104 if (!err)
00105 {
00106
00107 boost::asio::async_write(socket_, request_,
00108 boost::bind(&http_client::handle_write_request, this,
00109 boost::asio::placeholders::error));
00110 }
00111 else if (endpoint_iterator != tcp::resolver::iterator())
00112 {
00113
00114 socket_.close();
00115 tcp::endpoint endpoint = *endpoint_iterator;
00116 socket_.async_connect(endpoint,
00117 boost::bind(&http_client::handle_connect, this,
00118 boost::asio::placeholders::error, ++endpoint_iterator));
00119 }
00120 else m_error << "Error: " << err.message() << "\n";
00121 }
00122
00123 void
00124 http_client::
00125 handle_write_request(const boost::system::error_code& err)
00126 {
00127 using namespace boost::asio;
00128 if (err) { m_error << "Error: " << err.message() << "\n"; return; }
00129
00130
00131
00132
00133 async_read_until(socket_, response_, "\r\n",
00134 boost::bind(&http_client::handle_read_status_line,
00135 this, placeholders::error));
00136 }
00137
00138 void
00139 http_client::
00140 handle_read_status_line(const boost::system::error_code& err)
00141 {
00142 if (err) { m_error << "Error: " << err << "\n"; return; }
00143
00144 using namespace boost::asio;
00145
00146 std::istream response_stream(&response_);
00147 response_stream >> m_http_version >> m_status_code;
00148 std::getline(response_stream, m_status_message);
00149 if (!response_stream || m_http_version.substr(0, 5) != "HTTP/")
00150 m_error << "Invalid response\n";
00151 else if (m_status_code != 200)
00152 m_error << "Response returned with status code " << m_status_code << "\n";
00153 else
00154 async_read_until(socket_, response_, "\r\n\r\n",
00155 boost::bind(&http_client::handle_read_headers, this,
00156 placeholders::error));
00157 }
00158
00159
00160 void
00161 http_client::
00162 handle_read_headers(const boost::system::error_code& err)
00163 {
00164 if (err) { m_error << "Error: " << err << "\n"; return; }
00165
00166
00167 std::istream response_stream(&response_);
00168 std::string line;
00169 while (std::getline(response_stream, line) && line != "\r")
00170 m_header.push_back(line);
00171
00172
00173 if (response_.size() > 0)
00174 m_content << &response_;
00175
00176 using namespace boost::asio;
00177
00178 async_read(socket_, response_, transfer_at_least(1),
00179 boost::bind(&http_client::handle_read_content, this,
00180 placeholders::error));
00181 }
00182
00183 void
00184 http_client::
00185 handle_read_content(const boost::system::error_code& err)
00186 {
00187 using namespace boost::asio;
00188 if(!err)
00189 {
00190
00191
00192 m_content << &response_;
00193 async_read(socket_, response_, transfer_at_least(1),
00194 boost::bind(&http_client::handle_read_content, this,
00195 placeholders::error));
00196 }
00197 else if (err != boost::asio::error::eof)
00198 {
00199 m_error << "Error: " << err << "\n";
00200 }
00201 }
00202
00203 std::string
00204 uri_encode(std::string const& in)
00205 {
00206 char buf[3 * in.size() + 1];
00207 size_t i = 0;
00208 for (unsigned char const* c = (unsigned char const*)in.c_str(); *c; ++c)
00209 {
00210
00211 if (*c == ' ') buf[i++] = '+';
00212 else if (*c == '.' || *c == '~' || *c == '_' || *c == '-') buf[i++] = *c;
00213 else if (*c < '0') i += sprintf(buf+i, "%%%02x", int(*c));
00214 else if (*c <= '9') buf[i++] = *c;
00215 else if (*c < 'A') i += sprintf(buf+i, "%%%02x", int(*c));
00216 else if (*c <= 'Z') buf[i++] = *c;
00217 else if (*c < 'a') i += sprintf(buf+i, "%%%02x", int(*c));
00218 else if (*c <= 'z') buf[i++] = *c;
00219 else i += sprintf(buf+i, "%%%x", int(*c));
00220 }
00221 buf[i] = 0;
00222 return std::string(buf);
00223 }
00224
00225 }