When you redirect, you cannot just "replace" a location on the existing request. You cannot even use the same socket, except in the rare cases when the redirected target is on the same TCP endpoint.
Because the host name, protocol and path might have changed, you do have to parse the location, get the scheme, host, path parts. Then you must do proper host resolution again, and make sure to use the right host name in the Host
header.
Here's a sample that shows requesting the Boost License at the "wrong" url http://boost.org/user/license.html
, which will promptly redirect to http://www.boost.org/user/license.html
.
NOTE I've used network::uri
to do the URI parsing for us: https://github.com/reBass/uri
Demo
#include <iostream>
#include <boost/beast.hpp>
#include <boost/beast/http.hpp>
#include <network/uri.hpp>
#include <boost/asio.hpp>
#include <string>
using boost::asio::ip::tcp;
namespace http = boost::beast::http;
struct Requester {
void do_request(std::string const& url) {
network::uri u{url};
auto const lookup = resolver_.resolve( tcp::resolver::query(u.host().to_string(), u.scheme().to_string()) );
// Set up an HTTP GET request message
tcp::socket socket{ios};
boost::asio::connect(socket, lookup);
http::request<http::string_body> req{http::verb::get, u.path().to_string(), 11};
req.keep_alive(true);
req.set(http::field::host, u.host().to_string());
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
std::cout << "Target: " << url << "\n";
std::cout << req << "\n";
http::write(socket, req);
boost::beast::flat_buffer buffer;
http::response<http::dynamic_body> res;
http::read(socket, buffer, res);
switch(res.base().result_int()) {
case 301:
std::cout << "Redirecting.....\n";
do_request(res.base()["Location"].to_string());
break;
case 200:
std::cout << res << "\n";
break;
default:
std::cout << "Unexpected HTTP status " << res.result_int() << "\n";
break;
}
}
private:
boost::asio::io_service ios;
tcp::resolver resolver_{ios};
};
int main() {
try {
Requester requester;
requester.do_request("http://boost.org/users/license.html"); // redirects to http://www.boost.org/...
} catch(std::exception const& e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
This prints:
Target: http://boost.org/users/license.html
GET /users/license.html HTTP/1.1
Host: boost.org
User-Agent: Boost.Beast/109
Redirecting.....
Target: http://www.boost.org/users/license.html
GET /users/license.html HTTP/1.1
Host: www.boost.org
User-Agent: Boost.Beast/109
HTTP/1.1 200 OK
Date: Sun, 27 Aug 2017 22:25:20 GMT
Server: Apache/2.2.15 (CentOS)
Accept-Ranges: bytes
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
90fd
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Boost Software License</title>
<meta http-equiv="Content-Type" content="text/html; charset=us-ascii" />
<link rel="icon" href="/favicon.ico" type="image/ico" />
<link rel="stylesheet" type="text/css" href="../style-v2/section-boost.css" />
<!--[if IE 7]> <style type="text/css"> body { behavior: url(/style-v2/csshover3.htc); } </style> <![endif]-->
</head><!--
Note: Editing website content is documented at:
http://www.boost.org/development/website_updating.html
-->
<body>
ENTIRE LICENSE BODY SNIPPED
</body>
</html>
0
https:/ /www.domain.com/target/xxx/
– Roque