Imported Upstream version 1.64.0
[platform/upstream/boost.git] / libs / asio / example / cpp03 / http / client / async_client.cpp
1 //
2 // async_client.cpp
3 // ~~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2017 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #include <iostream>
12 #include <istream>
13 #include <ostream>
14 #include <string>
15 #include <boost/asio.hpp>
16 #include <boost/bind.hpp>
17
18 using boost::asio::ip::tcp;
19
20 class client
21 {
22 public:
23   client(boost::asio::io_service& io_service,
24       const std::string& server, const std::string& path)
25     : resolver_(io_service),
26       socket_(io_service)
27   {
28     // Form the request. We specify the "Connection: close" header so that the
29     // server will close the socket after transmitting the response. This will
30     // allow us to treat all data up until the EOF as the content.
31     std::ostream request_stream(&request_);
32     request_stream << "GET " << path << " HTTP/1.0\r\n";
33     request_stream << "Host: " << server << "\r\n";
34     request_stream << "Accept: */*\r\n";
35     request_stream << "Connection: close\r\n\r\n";
36
37     // Start an asynchronous resolve to translate the server and service names
38     // into a list of endpoints.
39     tcp::resolver::query query(server, "http");
40     resolver_.async_resolve(query,
41         boost::bind(&client::handle_resolve, this,
42           boost::asio::placeholders::error,
43           boost::asio::placeholders::iterator));
44   }
45
46 private:
47   void handle_resolve(const boost::system::error_code& err,
48       tcp::resolver::iterator endpoint_iterator)
49   {
50     if (!err)
51     {
52       // Attempt a connection to each endpoint in the list until we
53       // successfully establish a connection.
54       boost::asio::async_connect(socket_, endpoint_iterator,
55           boost::bind(&client::handle_connect, this,
56             boost::asio::placeholders::error));
57     }
58     else
59     {
60       std::cout << "Error: " << err.message() << "\n";
61     }
62   }
63
64   void handle_connect(const boost::system::error_code& err)
65   {
66     if (!err)
67     {
68       // The connection was successful. Send the request.
69       boost::asio::async_write(socket_, request_,
70           boost::bind(&client::handle_write_request, this,
71             boost::asio::placeholders::error));
72     }
73     else
74     {
75       std::cout << "Error: " << err.message() << "\n";
76     }
77   }
78
79   void handle_write_request(const boost::system::error_code& err)
80   {
81     if (!err)
82     {
83       // Read the response status line. The response_ streambuf will
84       // automatically grow to accommodate the entire line. The growth may be
85       // limited by passing a maximum size to the streambuf constructor.
86       boost::asio::async_read_until(socket_, response_, "\r\n",
87           boost::bind(&client::handle_read_status_line, this,
88             boost::asio::placeholders::error));
89     }
90     else
91     {
92       std::cout << "Error: " << err.message() << "\n";
93     }
94   }
95
96   void handle_read_status_line(const boost::system::error_code& err)
97   {
98     if (!err)
99     {
100       // Check that response is OK.
101       std::istream response_stream(&response_);
102       std::string http_version;
103       response_stream >> http_version;
104       unsigned int status_code;
105       response_stream >> status_code;
106       std::string status_message;
107       std::getline(response_stream, status_message);
108       if (!response_stream || http_version.substr(0, 5) != "HTTP/")
109       {
110         std::cout << "Invalid response\n";
111         return;
112       }
113       if (status_code != 200)
114       {
115         std::cout << "Response returned with status code ";
116         std::cout << status_code << "\n";
117         return;
118       }
119
120       // Read the response headers, which are terminated by a blank line.
121       boost::asio::async_read_until(socket_, response_, "\r\n\r\n",
122           boost::bind(&client::handle_read_headers, this,
123             boost::asio::placeholders::error));
124     }
125     else
126     {
127       std::cout << "Error: " << err << "\n";
128     }
129   }
130
131   void handle_read_headers(const boost::system::error_code& err)
132   {
133     if (!err)
134     {
135       // Process the response headers.
136       std::istream response_stream(&response_);
137       std::string header;
138       while (std::getline(response_stream, header) && header != "\r")
139         std::cout << header << "\n";
140       std::cout << "\n";
141
142       // Write whatever content we already have to output.
143       if (response_.size() > 0)
144         std::cout << &response_;
145
146       // Start reading remaining data until EOF.
147       boost::asio::async_read(socket_, response_,
148           boost::asio::transfer_at_least(1),
149           boost::bind(&client::handle_read_content, this,
150             boost::asio::placeholders::error));
151     }
152     else
153     {
154       std::cout << "Error: " << err << "\n";
155     }
156   }
157
158   void handle_read_content(const boost::system::error_code& err)
159   {
160     if (!err)
161     {
162       // Write all of the data that has been read so far.
163       std::cout << &response_;
164
165       // Continue reading remaining data until EOF.
166       boost::asio::async_read(socket_, response_,
167           boost::asio::transfer_at_least(1),
168           boost::bind(&client::handle_read_content, this,
169             boost::asio::placeholders::error));
170     }
171     else if (err != boost::asio::error::eof)
172     {
173       std::cout << "Error: " << err << "\n";
174     }
175   }
176
177   tcp::resolver resolver_;
178   tcp::socket socket_;
179   boost::asio::streambuf request_;
180   boost::asio::streambuf response_;
181 };
182
183 int main(int argc, char* argv[])
184 {
185   try
186   {
187     if (argc != 3)
188     {
189       std::cout << "Usage: async_client <server> <path>\n";
190       std::cout << "Example:\n";
191       std::cout << "  async_client www.boost.org /LICENSE_1_0.txt\n";
192       return 1;
193     }
194
195     boost::asio::io_service io_service;
196     client c(io_service, argv[1], argv[2]);
197     io_service.run();
198   }
199   catch (std::exception& e)
200   {
201     std::cout << "Exception: " << e.what() << "\n";
202   }
203
204   return 0;
205 }