diff --git a/PageCompiler/doc/PageCompilerUserGuide.page b/PageCompiler/doc/PageCompilerUserGuide.page index 718deb0cc..ef3b94c1a 100644 --- a/PageCompiler/doc/PageCompilerUserGuide.page +++ b/PageCompiler/doc/PageCompilerUserGuide.page @@ -16,8 +16,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; @@ -244,6 +244,10 @@ Allows to specify a language tag (e.g., "en") that will be sent in the response Content-Language header if the client sends an Accept-Language header in the request. +!contentSecurityPolicy + +Allows to specify the value of the HTTP Content-Security-Policy header. + !chunked Allows you to specify whether the response is sent using chunked transfer encoding. diff --git a/PageCompiler/src/CodeWriter.cpp b/PageCompiler/src/CodeWriter.cpp index fbb621cfe..f8c0f1531 100644 --- a/PageCompiler/src/CodeWriter.cpp +++ b/PageCompiler/src/CodeWriter.cpp @@ -36,13 +36,13 @@ void CodeWriter::writeHeader(std::ostream& ostr, const std::string& headerFileNa beginGuard(ostr, headerFileName); writeHeaderIncludes(ostr); ostr << "\n\n"; - + std::string decls(_page.headerDecls().str()); if (!decls.empty()) { ostr << decls << "\n\n"; } - + beginNamespace(ostr); writeHandlerClass(ostr); writeFactoryClass(ostr); @@ -73,13 +73,13 @@ void CodeWriter::writeImpl(std::ostream& ostr, const std::string& headerFileName } beginNamespace(ostr); - + std::string path = _page.get("page.path", ""); if (!path.empty()) { ostr << "\tconst std::string " << _class << "::PATH(\"" << path << "\");\n\n\n"; } - + writeConstructor(ostr); writeHandler(ostr); writeFactory(ostr); @@ -124,7 +124,7 @@ void CodeWriter::beginGuard(std::ostream& ostr, const std::string& headerFileNam std::string guard(p.getBaseName()); Poco::translateInPlace(guard, ".-", "__"); guard += "_INCLUDED"; - + ostr << "#ifndef " << guard << "\n"; ostr << "#define " << guard << "\n"; ostr << "\n\n"; @@ -157,13 +157,13 @@ void CodeWriter::handlerClass(std::ostream& ostr, const std::string& base, const } ostr << "\tvoid handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response);\n"; writeHandlerMembers(ostr); - + std::string path = _page.get("page.path", ""); if (!path.empty()) { ostr << "\n\tstatic const std::string PATH;\n"; } - + ostr << "};\n"; } @@ -311,13 +311,14 @@ void CodeWriter::writeResponse(std::ostream& ostr) { std::string contentType(_page.get("page.contentType", "text/html")); std::string contentLang(_page.get("page.contentLanguage", "")); + std::string contentSecurityPolicy(_page.get("page.contentSecurityPolicy", "")); std::string cacheControl(_page.get("page.cacheControl", "")); bool buffered(_page.getBool("page.buffered", false)); bool chunked(_page.getBool("page.chunked", !buffered)); bool compressed(_page.getBool("page.compressed", false)); if (buffered) compressed = false; if (compressed) chunked = true; - + if (chunked) { ostr << "\tresponse.setChunkedTransferEncoding(true);\n"; @@ -329,6 +330,10 @@ void CodeWriter::writeResponse(std::ostream& ostr) ostr << "\tif (request.has(\"Accept-Language\"))\n" << "\t\tresponse.set(\"Content-Language\", \"" << contentLang << "\");\n"; } + if (!contentSecurityPolicy.empty()) + { + ostr << "\tresponse.set(\"Content-Secure-Policy\", \"" << contentSecurityPolicy << "\");\n"; + } if (compressed) { ostr << "\tbool _compressResponse(request.hasToken(\"Accept-Encoding\", \"gzip\"));\n" @@ -350,7 +355,7 @@ void CodeWriter::writeContent(std::ostream& ostr) int compressionLevel(_page.getInt("page.compressionLevel", 1)); if (buffered) compressed = false; if (compressed) chunked = true; - + if (buffered) { ostr << "\tstd::stringstream responseStream;\n"; @@ -359,7 +364,7 @@ void CodeWriter::writeContent(std::ostream& ostr) { ostr << "\tresponse.setContentLength(static_cast(responseStream.tellp()));\n"; } - ostr << "\tPoco::StreamCopier::copyStream(responseStream, response.send());\n"; + ostr << "\tPoco::StreamCopier::copyStream(responseStream, response.send());\n"; } else if (compressed) { @@ -383,7 +388,7 @@ std::string CodeWriter::cleanupHandler(std::string handler) static const std::string NEWLINE_WRITE("\tresponseStream << \"\\n\";\n"); static const std::string DOUBLE_NEWLINE_WRITE("\tresponseStream << \"\\n\";\n\tresponseStream << \"\\n\";\n"); static const std::string EMPTY; - + // remove empty writes Poco::replaceInPlace(handler, EMPTY_WRITE, EMPTY); // remove consecutive newlines diff --git a/PageCompiler/src/PageCompiler.cpp b/PageCompiler/src/PageCompiler.cpp index e52127ec6..2436e6607 100644 --- a/PageCompiler/src/PageCompiler.cpp +++ b/PageCompiler/src/PageCompiler.cpp @@ -54,7 +54,7 @@ using Poco::OutputLineEndingConverter; class CompilerApp: public Application { public: - CompilerApp(): + CompilerApp(): _helpRequested(false), _generateOSPCode(false), _generateApacheCode(false), @@ -62,13 +62,13 @@ public: { } -protected: +protected: void initialize(Application& self) { loadConfiguration(); // load default configuration files, if present Application::initialize(self); } - + void defineOptions(OptionSet& options) { Application::defineOptions(options); @@ -80,7 +80,7 @@ protected: .callback(OptionCallback(this, &CompilerApp::handleHelp))); options.addOption( - Option("define", "D", + Option("define", "D", "Define a configuration property. A configuration property " "defined with this option can be referenced in the input " "page file, using the following syntax: ${}.") @@ -88,7 +88,7 @@ protected: .repeatable(true) .argument("=") .callback(OptionCallback(this, &CompilerApp::handleDefine))); - + options.addOption( Option("config-file", "f", "Load configuration data from the given file.") .required(false) @@ -142,18 +142,18 @@ protected: .repeatable(false) .callback(OptionCallback(this, &CompilerApp::handleNoLine))); } - + void handleHelp(const std::string& name, const std::string& value) { _helpRequested = true; stopOptionsProcessing(); } - + void handleDefine(const std::string& name, const std::string& value) { defineProperty(value); } - + void handleConfig(const std::string& name, const std::string& value) { loadConfiguration(value); @@ -183,19 +183,19 @@ protected: void handleOSP(const std::string& name, const std::string& value) { - _generateOSPCode = true; + _generateOSPCode = true; } void handleApache(const std::string& name, const std::string& value) { _generateApacheCode = true; } - + void handleNoLine(const std::string& name, const std::string& value) { _emitLineDirectives = false; } - + void displayHelp() { HelpFormatter helpFormatter(options()); @@ -204,7 +204,7 @@ protected: helpFormatter.setHeader( "\n" "The POCO C++ Server Page Compiler.\n" - "Copyright (c) 2008-2018 by Applied Informatics Software Engineering GmbH.\n" + "Copyright (c) 2008-2019 by Applied Informatics Software Engineering GmbH.\n" "All rights reserved.\n\n" "This program compiles web pages containing embedded C++ code " "into a C++ class that can be used with the HTTP server " @@ -218,7 +218,7 @@ protected: helpFormatter.setIndent(8); helpFormatter.format(std::cout); } - + void defineProperty(const std::string& def) { std::string name; @@ -245,7 +245,7 @@ protected: { compile(*it); } - + return Application::EXIT_OK; } @@ -257,7 +257,7 @@ protected: pageReader.parse(srcStream); Path p(path); - + if (page.has("page.class")) { clazz = page.get("page.class"); @@ -266,15 +266,15 @@ protected: { clazz = p.getBaseName() + "Handler"; clazz[0] = Poco::Ascii::toUpper(clazz[0]); - } + } } - + void write(const std::string& path, const Page& page, const std::string& clazz) { Path p(path); config().setString("inputFileName", p.getFileName()); config().setString("inputFilePath", p.toString()); - + DateTime now; config().setString("dateTime", DateTimeFormatter::format(now, DateTimeFormat::SORTABLE_FORMAT)); @@ -293,12 +293,12 @@ protected: { p = Path(_outputDir, p.getBaseName()); } - + if (!_base.empty()) { p.setBaseName(_base); } - + p.setExtension("cpp"); std::string implPath = p.toString(); std::string implFileName = p.getFileName(); @@ -325,7 +325,7 @@ protected: writeFileHeader(headerLEC); pCodeWriter->writeHeader(headerLEC, headerFileName); } - + void compile(const std::string& path) { Page page;