forked from microsoft/vscode-remote-try-cpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhttp_client_coro.cpp
159 lines (135 loc) · 4.7 KB
/
http_client_coro.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
//
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
//------------------------------------------------------------------------------
//
// Example: HTTP client, coroutine
//
//------------------------------------------------------------------------------
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/beast/http/read.hpp>
#include <boost/beast/version.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <string>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace http = boost::beast::http; // from <boost/beast/http.hpp>
//------------------------------------------------------------------------------
// Report a failure
void
fail(boost::system::error_code ec, char const* what)
{
std::cerr << what << ": " << ec.message() << "\n";
}
// Performs an HTTP GET and prints the response
void
do_session(
std::string const& host,
std::string const& port,
std::string const& target,
int version,
boost::asio::io_context& ioc,
boost::asio::yield_context yield)
{
boost::system::error_code ec;
// These objects perform our I/O
tcp::resolver resolver{ioc};
tcp::socket socket{ioc};
// Look up the domain name
auto const results = resolver.async_resolve(host, port, yield[ec]);
if(ec)
return fail(ec, "resolve");
// Make the connection on the IP address we get from a lookup
boost::asio::async_connect(socket, results.begin(), results.end(), yield[ec]);
if(ec)
return fail(ec, "connect");
// Set up an HTTP GET request message
http::request<http::string_body> req{http::verb::get, target, version};
req.set(http::field::host, host);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
req.body() = "blah";
// Send the HTTP request to the remote host
http::async_write(socket, req, yield[ec]);
if(ec)
return fail(ec, "write");
// This buffer is used for reading and must be persisted
boost::beast::flat_buffer b;
#if 0
// Declare a container to hold the response
http::response<http::dynamic_body> res;
// Receive the HTTP response
http::async_read(socket, b, res, yield[ec]);
if(ec)
return fail(ec, "read");
// Write the message to standard out
std::cout << res << std::endl;
#else
using namespace boost::beast::http;
http::parser<false, buffer_body> p;
read_header(socket, b, p, ec);
assert(p.is_header_done());
for (auto it = p.get().begin(); it != p.get().end(); ++it)
std::cout << "header: " << it->name() << "=" << it->value() << std::endl;
while (!p.is_done())
{
char buf[10];
p.get().body().data = buf;
p.get().body().size = sizeof(buf);
read(socket, b, p, ec);
if (ec == error::need_buffer)
ec.assign(0, ec.category());
std::cout << "read " << sizeof(buf)-p.get().body().size << " bytes" << std::endl;
}
#endif
// Gracefully close the socket
socket.shutdown(tcp::socket::shutdown_both, ec);
// not_connected happens sometimes
// so don't bother reporting it.
//
if(ec && ec != boost::system::errc::not_connected)
return fail(ec, "shutdown");
// If we get here then the connection is closed gracefully
}
//------------------------------------------------------------------------------
int main(int argc, char** argv)
{
// Check command line arguments.
if(argc != 4 && argc != 5)
{
std::cerr <<
"Usage: http-client-coro <host> <port> <target> [<HTTP version: 1.0 or 1.1(default)>]\n" <<
"Example:\n" <<
" http-client-coro www.example.com 80 /\n" <<
" http-client-coro www.example.com 80 / 1.0\n";
return EXIT_FAILURE;
}
auto const host = argv[1];
auto const port = argv[2];
auto const target = argv[3];
int version = argc == 5 && !std::strcmp("1.0", argv[4]) ? 10 : 11;
// The io_context is required for all I/O
boost::asio::io_context ioc;
// Launch the asynchronous operation
boost::asio::spawn(ioc, std::bind(
&do_session,
std::string(host),
std::string(port),
std::string(target),
version,
std::ref(ioc),
std::placeholders::_1));
// Run the I/O service. The call will return when
// the get operation is complete.
ioc.run();
return EXIT_SUCCESS;
}