#include "external_command.h" #include #include #include #include #include #include "support/xerces_string_guard.h" #include "support/dom/result_node_facade.h" namespace { using InputXSLT::XercesStringGuard; inline bool isWrappedOutput(const XMLCh* nodeName) { return xercesc::XMLString::equals( nodeName, *XercesStringGuard("inputxslt_wrapper") ); } std::unique_ptr readOutput( boost::process::pistream& outputStream) { const std::string rawOutput( (std::istreambuf_iterator(outputStream)), (std::istreambuf_iterator()) ); if ( rawOutput.substr(0, 5) == "( rawOutput ); } else { return std::make_unique( "" + rawOutput + "" ); } } boost::optional importDocumentElement( std::stringstream* const outputStream, xercesc::DOMDocument* const domDocument ) { xercesc::XercesDOMParser parser; parser.setDoNamespaces(true); parser.parse(xalan::XSLTInputSource(*outputStream)); if ( parser.getErrorCount() == 0 ) { return boost::make_optional( domDocument->importNode( parser.getDocument()->getDocumentElement(), true ) ); } else { return boost::optional(); } } boost::process::context createContext( const InputXSLT::FilesystemContext& fsContext) { boost::process::context context; context.environment = boost::process::self::get_environment(); context.stdout_behavior = boost::process::capture_stream(); context.stdin_behavior = boost::process::capture_stream(); context.work_directory = boost::filesystem::canonical( fsContext.getBase().parent_path() ).string(); return context; } } namespace InputXSLT { DomDocumentCache::document_ptr FunctionExternalCommand::constructDocument( const FilesystemContext& fsContext, std::string command, boost::optional input ) const { DomDocumentCache::document_ptr domDocument{ DomDocumentCache::createDocument("content") }; boost::process::child commandProcess{ boost::process::launch_shell(command, createContext(fsContext)) }; if ( input ) { boost::process::postream& inputStream = commandProcess.get_stdin(); inputStream << *input; inputStream.close(); } std::unique_ptr outputStream{ readOutput(commandProcess.get_stdout()) }; boost::process::status status = commandProcess.wait(); ResultNodeFacade result(domDocument.get(), "command"); result.setAttribute("executed", command); result.setAttribute("code", std::to_string(status.exit_status())); if ( status.exited() ) { try { if ( boost::optional documentElement{ importDocumentElement( outputStream.get(), domDocument.get() ) } ) { if ( isWrappedOutput((*documentElement)->getNodeName()) ) { result.setContent( (*documentElement)->getChildNodes() ); } else { result.setContent(*documentElement); } result.setAttribute("result", "success"); } else { result.setAttribute("result", "error"); } } catch ( const xercesc::DOMException& exception ) { result.setAttribute("result", "error"); result.setValueNode( "error", *XercesStringGuard(exception.msg) ); } } else { result.setAttribute("result", "error"); } return domDocument; } }