mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-31 14:39:53 +01:00
added Poco::Net::escapeHTML() and Poco::Net::EscapeHTMLStream; PageCompiler now supports optional HTML-escaping of <%= %> expressions.
This commit is contained in:
parent
44c7d97d2e
commit
665a840692
@ -33,7 +33,8 @@ objects = \
|
||||
WebSocket WebSocketImpl \
|
||||
OAuth10Credentials OAuth20Credentials \
|
||||
PollSet UDPClient UDPServerParams \
|
||||
NTLMCredentials SSPINTLMCredentials HTTPNTLMCredentials
|
||||
NTLMCredentials SSPINTLMCredentials HTTPNTLMCredentials \
|
||||
EscapeHTMLStream
|
||||
|
||||
target = PocoNet
|
||||
target_version = $(LIBVERSION)
|
||||
|
89
Net/include/Poco/Net/EscapeHTMLStream.h
Normal file
89
Net/include/Poco/Net/EscapeHTMLStream.h
Normal file
@ -0,0 +1,89 @@
|
||||
//
|
||||
// EscapeHTMLStream.h
|
||||
//
|
||||
// Library: Net
|
||||
// Package: HTTP
|
||||
// Module: EscapeHTMLStream
|
||||
//
|
||||
// Definition of the EscapeHTMLStream class.
|
||||
//
|
||||
// Copyright (c) 1029, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#ifndef Net_EscapeHTMLStream_INCLUDED
|
||||
#define Net_EscapeHTMLStream_INCLUDED
|
||||
|
||||
|
||||
#include "Poco/Net/Net.h"
|
||||
#include "Poco/UnbufferedStreamBuf.h"
|
||||
#include <ostream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
class Net_API EscapeHTMLStreamBuf: public Poco::UnbufferedStreamBuf
|
||||
/// This stream buffer replaces all occurrences of special HTML
|
||||
/// characters < > " & with their respective character
|
||||
/// entities < > " &.
|
||||
{
|
||||
public:
|
||||
EscapeHTMLStreamBuf(std::ostream& ostr);
|
||||
/// Creates the EscapeHTMLStreamBuf and connects it
|
||||
/// to the given output stream.
|
||||
|
||||
~EscapeHTMLStreamBuf();
|
||||
/// Destroys the EscapeHTMLStreamBuf.
|
||||
|
||||
protected:
|
||||
int readFromDevice();
|
||||
int writeToDevice(char c);
|
||||
|
||||
private:
|
||||
std::ostream* _pOstr;
|
||||
};
|
||||
|
||||
|
||||
class Net_API EscapeHTMLIOS: public virtual std::ios
|
||||
/// The base class for EscapeHTMLOutputStream.
|
||||
{
|
||||
public:
|
||||
EscapeHTMLIOS(std::ostream& ostr);
|
||||
/// Creates the MailIOS and connects it
|
||||
/// to the given output stream.
|
||||
|
||||
~EscapeHTMLIOS();
|
||||
/// Destroys the stream.
|
||||
|
||||
EscapeHTMLStreamBuf* rdbuf();
|
||||
/// Returns a pointer to the underlying streambuf.
|
||||
|
||||
protected:
|
||||
EscapeHTMLStreamBuf _buf;
|
||||
};
|
||||
|
||||
|
||||
class Net_API EscapeHTMLOutputStream: public EscapeHTMLIOS, public std::ostream
|
||||
/// This stream replaces all occurrences of special HTML
|
||||
/// characters < > " & with their respective character
|
||||
/// entities < > " &.
|
||||
{
|
||||
public:
|
||||
EscapeHTMLOutputStream(std::ostream& ostr);
|
||||
/// Creates the MailOutputStream and connects it
|
||||
/// to the given input stream.
|
||||
|
||||
~EscapeHTMLOutputStream();
|
||||
/// Destroys the MailOutputStream.
|
||||
};
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
#endif // Net_EscapeHTMLStream_INCLUDED
|
@ -81,7 +81,12 @@ void Net_API uninitializeNetwork();
|
||||
/// (Windows only, no-op elsewhere)
|
||||
|
||||
|
||||
}} // namespace Poco::Net
|
||||
std::string htmlize(const std::string& str);
|
||||
/// Returns a copy of html with reserved HTML
|
||||
/// characters (<, >, ", &) propery escaped.
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
//
|
||||
|
92
Net/src/EscapeHTMLStream.cpp
Normal file
92
Net/src/EscapeHTMLStream.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
//
|
||||
// EscapeHTMLStream.cpp
|
||||
//
|
||||
// Library: Net
|
||||
// Package: Mail
|
||||
// Module: EscapeHTMLStream
|
||||
//
|
||||
// Copyright (c) 2019, Applied Informatics Software Engineering GmbH.
|
||||
// and Contributors.
|
||||
//
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
//
|
||||
|
||||
|
||||
#include "Poco/Net/EscapeHTMLStream.h"
|
||||
|
||||
|
||||
namespace Poco {
|
||||
namespace Net {
|
||||
|
||||
|
||||
EscapeHTMLStreamBuf::EscapeHTMLStreamBuf(std::ostream& ostr):
|
||||
_pOstr(&ostr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLStreamBuf::~EscapeHTMLStreamBuf()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int EscapeHTMLStreamBuf::readFromDevice()
|
||||
{
|
||||
return std::char_traits<char>::eof();
|
||||
}
|
||||
|
||||
|
||||
int EscapeHTMLStreamBuf::writeToDevice(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '<':
|
||||
*_pOstr << "<";
|
||||
break;
|
||||
case '>':
|
||||
*_pOstr << ">";
|
||||
break;
|
||||
case '"':
|
||||
*_pOstr << """;
|
||||
break;
|
||||
case '&':
|
||||
*_pOstr << "&";
|
||||
break;
|
||||
default:
|
||||
_pOstr->put(c);
|
||||
break;
|
||||
}
|
||||
return charToInt(c);
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLIOS::EscapeHTMLIOS(std::ostream& ostr): _buf(ostr)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLIOS::~EscapeHTMLIOS()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLStreamBuf* EscapeHTMLIOS::rdbuf()
|
||||
{
|
||||
return &_buf;
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLOutputStream::EscapeHTMLOutputStream(std::ostream& ostr):
|
||||
EscapeHTMLIOS(ostr),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
EscapeHTMLOutputStream::~EscapeHTMLOutputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
@ -42,6 +42,26 @@ void Net_API uninitializeNetwork()
|
||||
}
|
||||
|
||||
|
||||
std::string htmlize(const std::string& str)
|
||||
{
|
||||
std::string::const_iterator it(str.begin());
|
||||
std::string::const_iterator end(str.end());
|
||||
std::string html;
|
||||
for (; it != end; ++it)
|
||||
{
|
||||
switch (*it)
|
||||
{
|
||||
case '<': html += "<"; break;
|
||||
case '>': html += ">"; break;
|
||||
case '"': html += """; break;
|
||||
case '&': html += "&"; break;
|
||||
default: html += *it; break;
|
||||
}
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Net
|
||||
|
||||
|
||||
|
@ -2,11 +2,16 @@ POCO C++ Server Page Compiler User Guide
|
||||
POCO PageCompiler
|
||||
|
||||
!!!Introduction
|
||||
|
||||
PageCompiler is a command line tool that translates HTML files (and other kinds of files) into
|
||||
C++ code, more precisely, subclasses of Poco::Net::HTTPRequestHandler.
|
||||
The source files can contain special directives that allow embedding of C++ code.
|
||||
The syntax of these directives is based on the syntax used for
|
||||
Java Server Pages (JSP) and Active Server Pages (ASP).
|
||||
Java Server Pages (JSP), Active Server Pages (ASP) or Embedded JavaScript (EJS) templating.
|
||||
|
||||
This makes PageCompiler a C++-based HTML templating system. Since the translation of
|
||||
the HTML template into a C++ class happens at compile time, runtime performance is
|
||||
excellent.
|
||||
|
||||
The following introductory sample shows the code for a simple page that displays the
|
||||
current date and time.
|
||||
@ -16,8 +21,8 @@ current date and time.
|
||||
#include "Poco/DateTime.h"
|
||||
#include "Poco/DateTimeFormatter.h"
|
||||
#include "Poco/DateTimeFormat.h"
|
||||
|
||||
|
||||
|
||||
|
||||
using Poco::DateTime;
|
||||
using Poco::DateTimeFormatter;
|
||||
using Poco::DateTimeFormat;
|
||||
@ -88,11 +93,24 @@ is required.
|
||||
|
||||
The result of any valid C++ expression can be directly inserted into the page,
|
||||
provided the result can be written to an output stream. Note that the expression
|
||||
must not end with a semicolon.
|
||||
must not end with a semicolon. If HTML escape mode is enabled (new in POCO C++ Libraries
|
||||
release 1.10.0), HTML special characters < > " &
|
||||
will be replaced with corresponding character entities.
|
||||
|
||||
<%= <expression> %>
|
||||
----
|
||||
|
||||
An alternative form of this is:
|
||||
|
||||
<%- <expression> %>
|
||||
----
|
||||
|
||||
The latter form always copies the result of expression to the page verbatim,
|
||||
without escaping special HTML characters.
|
||||
|
||||
Note that if escape mode is disabled, both forms are equivalent.
|
||||
|
||||
|
||||
!!Scriptlet
|
||||
|
||||
Arbitrary C++ code fragments can be included using the Scriptlet directive.
|
||||
@ -214,6 +232,13 @@ constructors of the base class must also accept a single argument of the specifi
|
||||
|
||||
Cannot be used together with <[context]>.
|
||||
|
||||
!escape
|
||||
|
||||
Enable (set to <[true]>) or disable (<[false]>, default) HTML escape mode.
|
||||
If enabled, the result of any expression enclosed in <%= %> tags will be HTML-escaped,
|
||||
which means HTML special characters < > " & will be replaced by corresponding
|
||||
character entities.
|
||||
|
||||
!export
|
||||
|
||||
Allows to specify a DLL import/export directive that is being added to the request
|
||||
@ -378,6 +403,10 @@ system (e.g., <[/help]> on Windows, <[--help]> or <[-h]> on Unix).
|
||||
* config-file (f): load configuration properties from a file
|
||||
* osp (O): add factory class definition/implementation for use with OSP
|
||||
* apache (A): add factory class definition/implementation and shared library manifest for use with ApacheConnector
|
||||
* escape (e): make HTML-escape mode default for all pages
|
||||
|
||||
Run the PageCompiler with the --help option to see all available options.
|
||||
|
||||
|
||||
!!Configuration Properties
|
||||
|
||||
|
@ -55,6 +55,10 @@ void CodeWriter::writeImpl(std::ostream& ostr, const std::string& headerFileName
|
||||
{
|
||||
ostr << "#include \"" << headerFileName << "\"\n";
|
||||
writeImplIncludes(ostr);
|
||||
if (_page.getBool("page.escape", false))
|
||||
{
|
||||
ostr << "#include \"Poco/Net/EscapeHTMLStream.h\"\n";
|
||||
}
|
||||
if (_page.getBool("page.compressed", false))
|
||||
{
|
||||
ostr << "#include \"Poco/DeflatingStream.h\"\n";
|
||||
@ -349,6 +353,7 @@ void CodeWriter::writeResponse(std::ostream& ostr)
|
||||
|
||||
void CodeWriter::writeContent(std::ostream& ostr)
|
||||
{
|
||||
bool escape(_page.getBool("page.escape", false));
|
||||
bool buffered(_page.getBool("page.buffered", false));
|
||||
bool chunked(_page.getBool("page.chunked", !buffered));
|
||||
bool compressed(_page.getBool("page.compressed", false));
|
||||
@ -359,6 +364,10 @@ void CodeWriter::writeContent(std::ostream& ostr)
|
||||
if (buffered)
|
||||
{
|
||||
ostr << "\tstd::stringstream responseStream;\n";
|
||||
if (escape)
|
||||
{
|
||||
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
|
||||
}
|
||||
ostr << cleanupHandler(_page.handler().str());
|
||||
if (!chunked)
|
||||
{
|
||||
@ -371,12 +380,20 @@ void CodeWriter::writeContent(std::ostream& ostr)
|
||||
ostr << "\tstd::ostream& _responseStream = response.send();\n"
|
||||
<< "\tPoco::DeflatingOutputStream _gzipStream(_responseStream, Poco::DeflatingStreamBuf::STREAM_GZIP, " << compressionLevel << ");\n"
|
||||
<< "\tstd::ostream& responseStream = _compressResponse ? _gzipStream : _responseStream;\n";
|
||||
if (escape)
|
||||
{
|
||||
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
|
||||
}
|
||||
ostr << cleanupHandler(_page.handler().str());
|
||||
ostr << "\tif (_compressResponse) _gzipStream.close();\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
ostr << "\tstd::ostream& responseStream = response.send();\n";
|
||||
if (escape)
|
||||
{
|
||||
ostr << "\tPoco::Net::EscapeHTMLOutputStream _escapeStream(responseStream);\n";
|
||||
}
|
||||
ostr << cleanupHandler(_page.handler().str());
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,8 @@ public:
|
||||
_helpRequested(false),
|
||||
_generateOSPCode(false),
|
||||
_generateApacheCode(false),
|
||||
_emitLineDirectives(true)
|
||||
_emitLineDirectives(true),
|
||||
_escape(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -141,6 +142,12 @@ protected:
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleNoLine)));
|
||||
|
||||
options.addOption(
|
||||
Option("escape", "e", "Escape special HTML characters (<, >, \", &) in <%= %> expressions.")
|
||||
.required(false)
|
||||
.repeatable(false)
|
||||
.callback(OptionCallback<CompilerApp>(this, &CompilerApp::handleEscape)));
|
||||
}
|
||||
|
||||
void handleHelp(const std::string& name, const std::string& value)
|
||||
@ -196,6 +203,11 @@ protected:
|
||||
_emitLineDirectives = false;
|
||||
}
|
||||
|
||||
void handleEscape(const std::string& name, const std::string& value)
|
||||
{
|
||||
_escape = true;
|
||||
}
|
||||
|
||||
void displayHelp()
|
||||
{
|
||||
HelpFormatter helpFormatter(options());
|
||||
@ -329,6 +341,12 @@ protected:
|
||||
void compile(const std::string& path)
|
||||
{
|
||||
Page page;
|
||||
|
||||
if (_escape)
|
||||
{
|
||||
page.set("page.escape", "true");
|
||||
}
|
||||
|
||||
std::string clazz;
|
||||
parse(path, page, clazz);
|
||||
write(path, page, clazz);
|
||||
@ -365,6 +383,7 @@ private:
|
||||
bool _generateOSPCode;
|
||||
bool _generateApacheCode;
|
||||
bool _emitLineDirectives;
|
||||
bool _escape;
|
||||
std::string _outputDir;
|
||||
std::string _headerOutputDir;
|
||||
std::string _headerPrefix;
|
||||
|
@ -21,6 +21,8 @@ const std::string PageReader::MARKUP_BEGIN("\tresponseStream << \"");
|
||||
const std::string PageReader::MARKUP_END("\";\n");
|
||||
const std::string PageReader::EXPR_BEGIN("\tresponseStream << (");
|
||||
const std::string PageReader::EXPR_END(");\n");
|
||||
const std::string PageReader::ESC_EXPR_BEGIN("\t_escapeStream << (");
|
||||
const std::string PageReader::ESC_EXPR_END(");\n");
|
||||
|
||||
|
||||
PageReader::PageReader(Page& page, const std::string& path):
|
||||
@ -128,6 +130,25 @@ void PageReader::parse(std::istream& pageStream)
|
||||
else _page.handler() << token;
|
||||
}
|
||||
else if (token == "<%=")
|
||||
{
|
||||
if (state == STATE_MARKUP)
|
||||
{
|
||||
_page.handler() << MARKUP_END;
|
||||
generateLineDirective(_page.handler());
|
||||
if (escape())
|
||||
{
|
||||
_page.handler() << ESC_EXPR_BEGIN;
|
||||
state = STATE_ESC_EXPR;
|
||||
}
|
||||
else
|
||||
{
|
||||
_page.handler() << EXPR_BEGIN;
|
||||
state = STATE_EXPR;
|
||||
}
|
||||
}
|
||||
else _page.handler() << token;
|
||||
}
|
||||
else if (token == "<%-")
|
||||
{
|
||||
if (state == STATE_MARKUP)
|
||||
{
|
||||
@ -146,6 +167,12 @@ void PageReader::parse(std::istream& pageStream)
|
||||
_page.handler() << MARKUP_BEGIN;
|
||||
state = STATE_MARKUP;
|
||||
}
|
||||
else if (state == STATE_ESC_EXPR)
|
||||
{
|
||||
_page.handler() << ESC_EXPR_END;
|
||||
_page.handler() << MARKUP_BEGIN;
|
||||
state = STATE_MARKUP;
|
||||
}
|
||||
else if (state == STATE_ATTR)
|
||||
{
|
||||
parseAttributes();
|
||||
@ -201,6 +228,7 @@ void PageReader::parse(std::istream& pageStream)
|
||||
_page.handler() << token;
|
||||
break;
|
||||
case STATE_EXPR:
|
||||
case STATE_ESC_EXPR:
|
||||
_page.handler() << token;
|
||||
break;
|
||||
case STATE_COMMENT:
|
||||
@ -387,3 +415,9 @@ void PageReader::generateLineDirective(std::ostream& ostr)
|
||||
ostr << "\"\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PageReader::escape() const
|
||||
{
|
||||
return _page.getBool("page.escape", false);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public:
|
||||
~PageReader();
|
||||
/// Destroys the PageReader.
|
||||
|
||||
void parse(std::istream& pageStream);
|
||||
void parse(std::istream& pageStream);
|
||||
/// Parses a HTML file containing server page directives,
|
||||
/// converts the file into C++ code and adds the code
|
||||
/// to the reader's Page object. Also parses page
|
||||
@ -53,6 +53,7 @@ protected:
|
||||
STATE_PREHANDLER,
|
||||
STATE_BLOCK,
|
||||
STATE_EXPR,
|
||||
STATE_ESC_EXPR,
|
||||
STATE_COMMENT,
|
||||
STATE_ATTR
|
||||
};
|
||||
@ -61,16 +62,19 @@ protected:
|
||||
static const std::string MARKUP_END;
|
||||
static const std::string EXPR_BEGIN;
|
||||
static const std::string EXPR_END;
|
||||
static const std::string ESC_EXPR_BEGIN;
|
||||
static const std::string ESC_EXPR_END;
|
||||
|
||||
void include(const std::string& path);
|
||||
void parseAttributes();
|
||||
void nextToken(std::istream& istr, std::string& token);
|
||||
void handleAttribute(const std::string& name, const std::string& value);
|
||||
std::string where() const;
|
||||
bool escape() const;
|
||||
|
||||
protected:
|
||||
void generateLineDirective(std::ostream& ostr);
|
||||
|
||||
|
||||
private:
|
||||
PageReader();
|
||||
PageReader(const PageReader&);
|
||||
|
Loading…
x
Reference in New Issue
Block a user