I am using a websocket server to parse some information from a program writing with c++ to a html page.
I am using the websocket server sample from POCO,
my problem is that the html page is generated from the web socket while i want to have the web page dependent from the websocket and that the web client can call the web socket server to give him data whenever it lunches an event like a click of a button.
I tried to call the websocket server from the html page but i think the problem is in the server, how can a server know that a certain page is calling him?
I used this script in my html page to call the websocket whenever i click a button.
function myFunction()
{
var soc_di="ws://127.0.0.1:9980/ws"
try {
soc_di.onopen = function() {
//document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
document.getElementById("demo").textContent = " websocket connection opened ";
}
soc_di.onmessage =function got_packet(msg) {
//document.getElementById("number").textContent = msg.data + "\n";
document.getElementById("des").textContent = msg.data + "\n";
}
soc_di.onclose = function(){
//document.getElementById("wsdi_statustd").style.backgroundColor = "#ff4040";
document.getElementById("demo").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
}
and here is the code when the websocket server generate the html page
class PageRequestHandler: public HTTPRequestHandler
/// Return a HTML document with some JavaScript creating
/// a WebSocket connection.
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
response.setChunkedTransferEncoding(true);
response.setContentType("text/html");
std::ostream& ostr = response.send();
ostr << "<html>";
ostr << "<head>";
ostr << "<title>WebSocketServer</title>";
ostr << "<script type=\"text/javascript\">";
ostr << "function WebSocketTest()";
ostr << "{";
ostr << " if (\"WebSocket\" in window)";
ostr << " {";
ostr << " var ws = new WebSocket(\"ws://" << request.serverAddress().toString() << "/ws\");";
ostr << " ws.onopen = function()";
ostr << " {";
ostr << " ws.send(\"Hello, world!\");";
ostr << " };";
ostr << " ws.onmessage = function(evt)";
ostr << " { ";
ostr << " var msg = evt.data;";
ostr << " alert(\"Message received: \" + msg);";
ostr << " ws.close();";
ostr << " };";
ostr << " ws.onclose = function()";
ostr << " { ";
ostr << " alert(\"WebSocket closed.\");";
ostr << " };";
ostr << " }";
ostr << " else";
ostr << " {";
ostr << " alert(\"This browser does not support WebSockets.\");";
ostr << " }";
ostr << "}";
ostr << "</script>";
ostr << "</head>";
ostr << "<body>";
ostr << " <h1>WebSocket Server</h1>";
ostr << " <p>Run WebSocket Script</p>";
ostr << "</body>";
ostr << "</html>";
}
};
Have a look at the websocket example.
In the example the RequestHandlerFactory looks for the browser to send an upgrade to websocket request. If it finds this request then the example returns a WebSocketRequestHandler that then reads the web socket stream using Poco::Net::WebSocket.
You probably need another HTTPRequestHandler class that is responsible for handling websockets.
class WebSocketRequestHandler: public HTTPRequestHandler
/// Handle a WebSocket connection.
{
public:
void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response)
{
Application& app = Application::instance();
try
{
WebSocket ws(request, response);
app.logger().information("WebSocket connection established.");
char buffer[1024];
int flags;
int n;
do
{
n = ws.receiveFrame(buffer, sizeof(buffer), flags);
app.logger().information(Poco::format("Frame received (length=%d, flags=0x%x).", n, unsigned(flags)));
ws.sendFrame(buffer, n, flags);
}
while (n > 0 || (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
app.logger().information("WebSocket connection closed.");
}
catch (WebSocketException& exc)
{
app.logger().log(exc);
switch (exc.code())
{
case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
response.set("Sec-WebSocket-Version", WebSocket::WEBSOCKET_VERSION);
// fallthrough
case WebSocket::WS_ERR_NO_HANDSHAKE:
case WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
case WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
response.setContentLength(0);
response.send();
break;
}
}
}
};
Related
I am new to learning C++ and for a class I am tasked with an assignment to create a parser for HTML files in C++. The program is to input a file name, and output that file's contents, how many lines, character, tags, links, comments, and what percent of characters are in tags.
I have most of the program complete, I am just stumbling on one part: how to count the number of tags in the HTML file. Below is what I have so far. My issue in particular is with lines 106-109, the part that starts with "if(fileChar == TAG)"
Other questions related to this topic either aren't answered, or are using libraries I am not allowed to.
Since this is for a class ideally I am looking for a method that does not involve libraries other than the ones listed in the header files. Any help would be much appreciated as I am currently banging my head against a wall :)
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main ()
{
const char TAG = '<', //marks the beginning of a tag
LINK = 'a', //marks the beginning of a link
COMMENT = '!'; //marks the beginning of a comment
char fileChar; //individual characters from the file
int charNum=0, //total characters in the file
tagNum=0, //total tags in the file
linkNum=0, //total links in the file
commentNum=0, //total comments in the file
tagChars=0, //number of chars in tags
lineNum=0, //number of lines in file
charPercent=0; //percent of chars in tags
int count = 0; //for counting
string fileName; //name of file
ifstream inFile;
//take in user input
cout << "========================================" << endl;
cout << " Welcome to the HTML File Analyzer!" << endl;
cout << "========================================" << endl << endl;
cout << "Please enter a valid file name (with no spaces): " << endl;
cin >> fileName;
inFile.open(fileName.c_str()); //opens the file
if(inFile) //tests if file is open
cout << "file IS open" << endl;
else
cout << "file NOT open" << endl;
while (!inFile) //error checking to ensure file exists
{
inFile.clear(); //clear false file
cout << endl << "Re-enter a valid filename: " << endl;
cin >> fileName;
inFile.open (fileName.c_str());
}
//display contents of file
cout << "========================================" << endl;
cout << " Contents of the File " << endl;
cout << "========================================" << endl << endl;
std:string line;
while(inFile) //print out contents of the file
{
getline(inFile, line);
cout << line << endl;
lineNum++; //add to line counter
const int size=line.length();
charNum = charNum + size;
cout << "The total number of characters entered is: " << charNum << endl;
}
inFile.open(fileName.c_str()); //reopen file
while(inFile)
{
if (fileChar == TAG)
{
tagNum++;
}
}
cout << "========================================" << endl;
cout << " End of Contents of File " << endl;
cout << "========================================" << endl << endl;
inFile.open(fileName.c_str());
while(inFile) //count chars
{
charNum = charNum + 1;
}
cout << "========================================" << endl;
cout << " Content Analysis " << endl;
cout << "========================================" << endl << endl;
cout << "Number of Lines: " << lineNum << endl;
cout << "Number of Tags: " << tagNum << endl;
cout << "Number of Comments: " << commentNum << endl;
cout << "Number of Links: " << linkNum << endl;
cout << "Number of Chars in File: " << charNum << endl;
cout << "Number of Chars in Tags: " << tagChars << endl;
cout << "Percent of Chars in Tags: " << charPercent << endl;
inFile.close ();
return (0);
}
Under the assumption that you are dealing with valid HTML5, we can distinguish five cases when you see a < character outside of a comment:
either it is the start of a comment and is followed by !--, or
either it is the start of a DOCTYPE and is followed by !DOCTYPE, or
either it is the start of a CDATA and is followed by ![CDATA[, or
it is an end tag and is followed by /, or
it is a start tag and is followed by a tag name.
while (inFile) {
inFile >> fileChar;
if (inFile != TAG) continue; // We are only interested in potential tag or comment starts.
inFile >> fileChar;
if (fileChar == '!') {
char after1, after2;
inFile >> after1 >> after2;
if (after1 == '-' && after2 == '-') {
// This is the start of a comment.
// We start eating chars until we see '-->' pass by.
std::string history = " ";
while (inFile) {
inFile >> fileChar;
if (history == "--" && fileChar == '>') {
// end of comment, stop this inner loop.
commentNum++;
break;
}
// Shift history and copy current character to recent history
history[0] = history[1];
history[1] = fileChar;
}
}
} else if (fileChar == '/') {
// This is a closing tag. Do nothing.
} else {
// This is the start of a tag. Read until the first non-letter, non-digit.
std::string tagName;
while (inFile) {
inFile >> fileChar;
if (std::isalnum(fileChar)) {
tagName.append(1, fileChar);
} else {
tagNum++;
if (tagName == "a") linkNum++;
}
}
}
}
Note that this is a very naïve implementation that only implements a part of the specification. It will probably break if you feed it malformed HTML. It definitely does not handle CDATA blocks (which will treat its contents as HTML instead of unparsed character data). I am not sure what you mean by "percent chars in tags", but that might be something you can track in the last else branch.
Finally, note that I wrote it as a single block. You are of course encouraged to factor it into smaller functions (read_comment or read_tag_name, for example) to increase legibility.
I have a homework problem which asks me to write a simple HTML validator which checks for matching start and end tags.
Here is my code and input file below.
void removeSpaces(std::string &str){
int count = 0;
for (int i = 0; str[i]; i++)
if (str[i] != ' ')
str[count++] = str[i];
str[count] = '\0';
}
bool isHtmlMatched(std::vector<std::string>& htmlTags){
std::stack<std::string> temp;
typedef std::vector<std::string>::const_iterator Iter;
for (int i = 0; i < htmlTags.size(); i++){
if (htmlTags[i][1] != '/')
temp.push(htmlTags[i]);
else{
if (temp.empty()) return false;
std::string open = temp.top().substr(1);
std::string close = htmlTags[i].substr(2);
std::cout << open << " " << close <<std::endl;
if (open != close){
std::cout << "Failed at where " << temp.top() << " didnt match with " << htmlTags[i] << std::endl;
return false;
}
else{
temp.pop();
}
}
}
if(temp.empty()){
return true;
}
else{
std::cout << " These start tags ";
while(!temp.empty()){
std::cout << temp.top() << " ";
temp.pop();
}
std::cout << "do not have a matching end tag " <<std::endl;
return false;
}
}
int main() {
std::vector<std::string> htmlTags;
std::string input_line;
std::ifstream file("Validhtml.txt");
std::string tag;
int line = 0;
while(std::getline(file, input_line)){
int pointer = 0;
int position_start = input_line.find("<",pointer);
while (position_start != std::string::npos){
if(input_line.find(">", position_start + 1) == std::string::npos){
std::cout << "INVALID HTML" << std::endl;
std::cout << "ERROR ON LINE " << line + 1 << std::endl;
return 0;
}
int position_end = input_line.find(">", position_start + 1);
tag = input_line.substr(position_start, position_end - position_start + 1);
removeSpaces(tag);
htmlTags.push_back(tag);
pointer = position_end + 1;
position_start = input_line.find("<", pointer);
}
line++;
}
for(int i = 0; i < htmlTags.size(); i++){
std::cout << htmlTags[i] << std::endl;
}
if(!isHtmlMatched(htmlTags)){
std::cout << "INVALID HTML" << std::endl;
}
else{
std::cout << "VALID HTML" << std::endl;
}
return 0;
}
Input file:
<html><
head></head><body> My HTML page
<p></p> <h2>Hello world! </ h2>
<ol><li> #myfiles</li>
</ol>
</body >
</html>
I currently have two problem with this code.
I don't know how to read tags that are split in different lines, for example the <head> tag at the end of the first and start of the second line of the input file.
Even after I removed all the white space, this program still won't recognize <h2> and </ h2> are a matching tag. Same issue goes for <body> and </body >
Hope someone can help me with this.
I worked on this for a bit and got something I think should work for you.
Here's how the code works: First, we open the html file and push it all into a string with no whitespace. Next, we send that string to a function to detect tags. Once a tag is detected, we try to see if its an opening or closing tag. We then save the tag to the correct container (either the opening_tags container or the closing_tags container). Finally, we run a series of tests on the two containers we have. (1) Are they the same size? (2) Are they empty (meaning no tags were detected)? (3) Do all tags in the opening_tags container correspond to a tag in the closing_tags container.
If all three of our tests are passed, then we can say the html file is valid (based on tag matching).
For the containers, I used hashsets (known as std::unordered_set in C++). This is because hashsets are really fast in inserting and removing elements. In your specific instance, the order of the tags shouldn't matter. However, keep in mind that, in an actual validator, it would matter greatly.
If you have any more questions on my code, feel free to ask! Without any more waiting, here's the code:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <unordered_set>
// Gets rid of all file white space and returns the string
std::string condense(std::ifstream&);
// Tests if all tags are matching and returns if they are
// (true) or if they aren't (false)
bool validate(const std::string&);
int main()
{
std::ifstream html_stream("input.html");
const std::string html_string = condense(html_stream);
const bool html_valid = validate(html_string);
// Prints the html string (mostly for debugging)
std::cout << html_string << '\n' << std::endl;
if (html_valid)
std::cout << "Valid HTML!" << std::endl;
else
std::cout << "Invalid HTML..." << std::endl;
}
std::string condense(std::ifstream& stream)
{
std::string file_no_whitespace;
if (stream.is_open())
{
std::string cur_token;
while (stream >> cur_token)
file_no_whitespace += cur_token;
}
else
std::cerr << "File is not open!" << std::endl;
return file_no_whitespace;
}
bool validate(const std::string& data)
{
// These should be the same size if the html is valid
// (based only on tag matching)
std::unordered_set<std::string> opening_tags, closing_tags;
// For tags like '<br />'
std::unordered_set<std::string> self_closing_tags;
// Keeps track of the current tag to push into either
// opening_tags or closing_tags
bool tagging_open;
// Process each character to make tags
for (size_t i = 0; i < data.size(); ++i)
{
const auto* cur_char = &data.at(i);
if (*cur_char == '<')
{
std::string cur_tag;
if (*(cur_char + 1) == '/')
{ // Test for closing tag
tagging_open = false;
i++;
cur_char++;
}
else // Tag is an opening tag
tagging_open = true;
i++;
cur_char++;
while (*cur_char != '>') // Until tag closes
{
cur_tag += *cur_char;
i++;
cur_char++;
}
// Test for self-closing tag
if (*(cur_char - 1) == '/')
self_closing_tags.insert(cur_tag);
// Not self-closing, so it's a normal type of tag
else if (tagging_open)
opening_tags.insert(cur_tag);
else if (!tagging_open)
closing_tags.insert(cur_tag);
}
}
// If the hashsets aren't the same size, then we automatically know
// there is at least one unmatched tag
if (opening_tags.size() != closing_tags.size())
return false;
// If the hashsets are both empty, then we know there are no tags
if (opening_tags.empty())
return false;
// If both above tests have been passed, we now need to make sure that
// every opening tag has a matching closing tag
std::vector<bool> tag_match(opening_tags.size(), false);
size_t tag_match_pos = 0;
for (const auto& tag : opening_tags)
{
auto closing_tag_itr = closing_tags.find(tag);
if (closing_tag_itr != std::end(closing_tags))
{
tag_match.at(tag_match_pos) = true;
tag_match_pos++;
// Remove match tag to avoid duplicates causing false-positives
closing_tags.erase(closing_tag_itr);
}
}
bool all_matched = true;
for (const auto& match : tag_match)
{ // Make sure all values in the 'tag_match' vector are true
if (!match)
{
all_matched = false;
break;
}
}
return all_matched;
}
I'm a newbie in c++ and I've been trying to search for an answer to this question but can hardly found an answer I'm trying to compress an html string body with zlib in gzip compression the compression gets done successfully but when I try to concatenate it to another string it won't concatenate at all rendering the body to be blank here is the compression code:
void compress_message(){
z_stream zs;
char outbuffer[32768];
long strlen = content.size();
int ret;
string outstring;
memset(&zs, 0, sizeof(zs));
if (deflateInit2(&zs,
Z_BEST_COMPRESSION,
Z_DEFLATED,
MOD_GZIP_ZLIB_WINDOWSIZE + 16,
MOD_GZIP_ZLIB_CFACTOR,
Z_DEFAULT_STRATEGY) != Z_OK
) {
throw(std::runtime_error("deflateInit2 failed while compressing."));
}
content = "";
zs.next_in = (Bytef*) content.data();
zs.avail_in = strlen;
do {
//cout << "compressing..." << endl;
zs.next_out = reinterpret_cast<Bytef*>(outbuffer);
zs.avail_out = sizeof(outbuffer);
ret = deflate(&zs, Z_FINISH);
if (content.size() < zs.total_out) {
// append the block to the output string
content.append(outbuffer,
zs.total_out - content.size());
}
} while (ret == Z_OK);
deflateEnd(&zs);
//cout << "original: " << content << endl;
if (ret != Z_STREAM_END) { // an error occurred that was not EOF
ostringstream oss;
oss << "Exception during zlib compression: (" << ret << ") " << zs.msg;
throw(std::runtime_error(oss.str()));
}
}
base64 conversion function:
string tobase64(string data) {
string code64,
output = "";
int i = 0,
j = 0;
unsigned int slen = data.size();
const char* bytes_to_encode;
code64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
unsigned char char_array_3[3],
char_array_4[4];
bytes_to_encode = data.c_str();
while(slen--){
char_array_3[i++] = bytes_to_encode[j++];
if(3 == i){
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for(i = 0; i < 4; i++){
output += code64[char_array_4[i]];
}
i = 0;
}
}
if (i)
{
for(j = i; j < 3; j++)
char_array_3[j] = '\0';
char_array_4[0] = ( char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
for (j = 0; (j < i + 1); j++)
output += code64[char_array_4[j]];
while((i++ < 3))
output += '=';
}
return output;
}
the string is successfully compressed but when I concatenate it to the string response like:
string final_content = ("HTTP/1.1 200 OK\r\n"+headers+"\r\n\r\n");
content = tobase64(content);
final_content += content;
I also tried
final_content.append(content);
They both have the same result the body is never concatenated the final_content when printed only shows:
HTTP/1.1 200 OK
...
Content-type: text/html
and the compressed string is never included have been trying to find answers online and couldn't figure it out please help. I'm working this on ubuntu 18.04
im trying to print an invoice in a4 format using qprint and QTextDocument with html ..but i couldn't find any solution to adjust the margin-left and margin-right of the html table...
my example
QString data;
m_printer.setPageSize(QPrinter::A4);
m_printer.setOrientation(QPrinter::Landscape);
QTextStream out(&m_strStream);
const int rowCount = m_TableWidget->model()->rowCount();
const int columnCount = m_TableWidget->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg("title")
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
out << "<thead><tr bgcolor=#f0f0f0>";
for (int column = 0; column < columnCount; column++)
if (!m_TableWidget->isColumnHidden(column))
out << QString("<th>%1</th>").arg(m_TableWidget->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr></thead>\n";
// data table
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if(column%7 == 1) {
QString data = m_TableWidget->model()->data(m_TableWidget->model()->index(0, column)).toString().simplified();
out << QString("<td colspan=7>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
} else if(column == 0){
QString data = m_TableWidget->model()->data(m_TableWidget->model()->index(0, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
for (int row = 1; row < rowCount; row++) {
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if(row==1 && column==1)
{ data =m_ComboBox->currentText().simplified();
}
if (!m_TableWidget->isColumnHidden(column)) {
data = m_TableWidget->model()->data(m_TableWidget->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
m_document = new QTextDocument();
m_document->setHtml(m_strStream);
m_dialog = new QPrintDialog(&m_printer, NULL);
if (m_dialog->exec() == QDialog::Accepted) {
m_document->print(&m_printer);
}
delete m_document;
Is there an alternative version of std::find_if that returns an iterator over all found elements, instead of just the first one?
Example:
bool IsOdd (int i) {
return ((i % 2) == 1);
}
std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
std::vector<int>::iterator it = find_if(v.begin(), v.end(), IsOdd);
for(; it != v.end(); ++it) {
std::cout << "odd: " << *it << std::endl;
}
You can just use a for loop:
for (std::vector<int>:iterator it = std::find_if(v.begin(), v.end(), IsOdd);
it != v.end();
it = std::find_if(++it, v.end(), IsOdd))
{
// ...
}
Alternatively, you can put your condition and action into a functor (performing the action only if the condition is true) and just use std::foreach.
in STL there isn't, but boost offers this funcionality:
boost::algorithm::find_all
First always try to come up with typical STL usage itself, you can go for boost as well. Here is more simplified form from the above mentioned answer by Charles.
vec_loc = find_if(v3.begin(), v3.end(), isOdd);
if (vec_loc != v3.end())
{
cout << "odd elem. found at " << (vec_loc - v3.begin()) << "and elem found is " << *vec_loc << endl;
++vec_loc;
}
for (;vec_loc != v3.end();vec_loc++)
{
vec_loc = find_if(vec_loc, v3.end(), isOdd);
if (vec_loc == v3.end())
break;
cout << "odd elem. found at " << (vec_loc - v3.begin()) << "and elem found is " << *vec_loc << endl;
}