2 * Copyright (C) 2009 by Aiwota Programmer
3 * aiwotaprog@tetteke.tk
5 * This file is part of Dialektos.
7 * Dialektos is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * Dialektos is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Dialektos. If not, see <http://www.gnu.org/licenses/>.
21 #include "http_client.hxx"
23 #include <boost/asio.hpp>
24 #include <boost/bind.hpp>
25 #include <boost/algorithm/string.hpp>
26 #include <boost/date_time/posix_time/posix_time.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/format.hpp>
34 #include "http_response.hxx"
35 #include "http_status_line.hxx"
43 AsyncClient::AsyncClient(
44 boost::asio::io_service& io_service, const std::string& uri,
45 const Header& header) :
46 resolver_(io_service),
57 const std::string host = header.get_host();
58 assert(!host.empty());
60 std::ostream stream(&request_);
62 stream << boost::format("GET %1% HTTP/1.0\r\n") % uri;
64 typedef std::map<std::string, std::string>::value_type PairType;
65 BOOST_FOREACH(const PairType& pair, header) {
66 stream << boost::format("%1%: %2%\r\n") % pair.first % pair.second;
68 stream << "\r\n" << std::flush;
70 boost::asio::ip::tcp::resolver::query query(host, "http");
71 resolver_.async_resolve(query,
72 boost::bind(&AsyncClient::handle_resolve, this,
73 boost::asio::placeholders::error,
74 boost::asio::placeholders::iterator));
77 void AsyncClient::handle_resolve(const boost::system::error_code& err,
78 boost::asio::ip::tcp::resolver::iterator endpoint_iterator) {
84 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
85 socket_.async_connect(endpoint,
86 boost::bind(&AsyncClient::handle_connect, this,
87 boost::asio::placeholders::error, ++endpoint_iterator));
90 void AsyncClient::handle_connect(const boost::system::error_code& err,
91 boost::asio::ip::tcp::resolver::iterator endpoint_iterator) {
93 boost::asio::async_write(socket_, request_,
94 boost::bind(&AsyncClient::handle_write_request, this,
95 boost::asio::placeholders::error));
96 } else if (endpoint_iterator != boost::asio::ip::tcp::resolver::iterator()) {
98 boost::asio::ip::tcp::endpoint endpoint = *endpoint_iterator;
99 socket_.async_connect(endpoint,
100 boost::bind(&AsyncClient::handle_connect, this,
101 boost::asio::placeholders::error, ++endpoint_iterator));
107 void AsyncClient::handle_write_request(const boost::system::error_code& err) {
113 boost::asio::async_read_until(socket_, response_, "\r\n",
114 boost::bind(&AsyncClient::handle_read_status_line, this,
115 boost::asio::placeholders::error));
118 void AsyncClient::handle_read_status_line(
119 const boost::system::error_code& err) {
125 std::istream stream(&response_);
127 stream >> http_version_;
128 stream >> status_code_;
130 std::string status_message_;
131 std::getline(stream, status_message_);
133 if (!stream || !boost::algorithm::starts_with(http_version_, "HTTP/")) {
134 std::cerr << "response is not HTTP" << std::endl;
138 boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
139 boost::bind(&AsyncClient::handle_read_headers, this,
140 boost::asio::placeholders::error));
143 void AsyncClient::handle_read_headers(const boost::system::error_code& err) {
149 std::istream stream(&response_);
151 while (std::getline(stream, line)) {
152 boost::algorithm::trim_right(line);
153 response_header_.set_header_from_line(line);
156 if (response_.size() > 0)
157 content_ << &response_ << std::flush;
159 boost::asio::async_read(socket_, response_,
160 boost::asio::transfer_at_least(1),
161 boost::bind(&AsyncClient::handle_read_content, this,
162 boost::asio::placeholders::error));
165 void AsyncClient::handle_read_content(const boost::system::error_code& err)
168 content_ << &response_ << std::flush;
170 boost::asio::async_read(socket_, response_,
171 boost::asio::transfer_at_least(1),
172 boost::bind(&AsyncClient::handle_read_content, this,
173 boost::asio::placeholders::error));
174 } else if (err != boost::asio::error::eof) {
179 Response AsyncClient::get_response() const {
180 std::stringstream ss;
181 ss << boost::format("%1% %2% %3%")
182 % http_version_ % status_code_ % status_message_;
183 std::string status_line = ss.str();
185 StatusLine status(http_version_, status_code_, status_message_, status_line);
186 return Response(status, response_header_, content_.str());
192 } // namespace dialektos