-
Notifications
You must be signed in to change notification settings - Fork 0
/
WebPage.cpp
149 lines (130 loc) · 3.44 KB
/
WebPage.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
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <string>
#include <iomanip>
#include <iostream>
#include "headers/WebPage.h"
#define HTTP_PORT "80"
using namespace std;
namespace asio = boost::asio;
namespace http = boost::beast::http;
/// <summary>
/// Function makes a request to HTTP server.
/// Reference used: https://www.boost.org/doc/libs/1_70_0/libs/beast/doc/html/beast/quick_start/http_client.html
/// </summary>
/// <returns>
/// The result of the request if the connection successful
/// Error string if the connection failed
/// </returns>
bool WebPage::request()
{
asio::io_context context; // Asio I/O space
asio::ip::tcp::resolver resolver(context); // DNS resolver object
asio::ip::tcp::socket socket(context); // Networking socket object
string domain = solveDomain(cutProtocol());
try {
asio::connect(socket, resolver.resolve(domain, HTTP_PORT)); // Establish connection with the target
}
catch (exception& e) {
return false; // Connection failed return
}
// Form HTTP request
string dir = solveDirectory(cutProtocol());
http::request<http::string_body> req(http::verb::get, dir, 11); // Make a request to the certain page
req.set(http::field::host, domain);
req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
// Send request
http::write(socket, req);
boost::beast::flat_buffer buffer; // Create buffer
http::response<http::dynamic_body> res;
http::read(socket, buffer, res); // Read response to the buffer
response = boost::beast::buffers_to_string(res.body().data()); // Translate buffer to string
socket.shutdown(asio::ip::tcp::socket::shutdown_both); // Shutdown the connection
return true; // Request succesful return
}
/**
* Parse domain from the URL
*/
string WebPage::solveDomain(string npURL)
{
if (npURL.find("/") == string::npos) {
return npURL;
}
else {
return npURL.substr(0, npURL.find("/"));
}
}
/**
* Parse page of the URL
*/
string WebPage::solveDirectory(string npURL)
{
if (npURL.find("/") == string::npos) {
return "/";
}
else {
return npURL.substr(npURL.find("/"));
}
}
/**
* Cut the protocol from the url if present
*/
string WebPage::cutProtocol()
{
if (url.find("//") != std::string::npos) {
return url.substr(url.find("//") + 2);
}
else {
return url;
}
}
/// <summary>
/// Check if the page content meets the requirments
/// </summary>
/// <returns>
/// True if content was found on the page
/// False if not
/// </returns>
bool WebPage::checkCondition() const
{
if (response.find(content) == string::npos) {
return false;
}
else {
return true;
}
}
/// <summary>
/// Print HTML representation of web page status
/// </summary>
string WebPage::getFormatHTML() const
{
ostringstream lineOut;
lineOut << "<a href=\"" << url <<"\">" << url << "</a>" <<" " << status << " " << responseTime << "ms" << "</p>";
return lineOut.str();
}
/**
* Overload for writing page information to log
*/
ostream& operator<<(ostream& out, const WebPage& targetPage)
{
out << setw(70) << left << targetPage.url
<< setw(15) << targetPage.status
<< setw(6) << right << targetPage.responseTime << "ms";
return out;
}
/**
* Overload for reading configuration from the file
*/
istream& operator>>(istream& in, WebPage& targetPage)
{
// Check if URL format is correct
if (!getline(in, targetPage.url, ';')) {
in.setstate(ios_base::failbit);
}
// Check is content requirment format is correct
if (!getline(in, targetPage.content)) {
in.setstate(ios_base::failbit);
}
return in;
}