1 /** @file 2 3 A brief file description 4 5 @section license License 6 7 Licensed to the Apache Software Foundation (ASF) under one 8 or more contributor license agreements. See the NOTICE file 9 distributed with this work for additional information 10 regarding copyright ownership. The ASF licenses this file 11 to you under the Apache License, Version 2.0 (the 12 "License"); you may not use this file except in compliance 13 with the License. You may obtain a copy of the License at 14 15 http://www.apache.org/licenses/LICENSE-2.0 16 17 Unless required by applicable law or agreed to in writing, software 18 distributed under the License is distributed on an "AS IS" BASIS, 19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 See the License for the specific language governing permissions and 21 limitations under the License. 22 */ 23 24 #pragma once 25 26 #include <string> 27 #include <map> 28 #include "lib/ComponentBase.h" 29 #include "lib/StringHash.h" 30 #include "lib/DocNode.h" 31 #include "EsiParser.h" 32 #include "HttpDataFetcher.h" 33 #include "Variables.h" 34 #include "Expression.h" 35 #include "SpecialIncludeHandler.h" 36 #include "HandlerManager.h" 37 38 class EsiProcessor : private EsiLib::ComponentBase 39 { 40 public: 41 enum UsePackedNodeResult { 42 PROCESS_IN_PROGRESS, 43 UNPACK_FAILURE, 44 PROCESS_SUCCESS, 45 PROCESS_FAILURE, 46 }; 47 48 EsiProcessor(const char *debug_tag, const char *parser_debug_tag, const char *expression_debug_tag, 49 EsiLib::ComponentBase::Debug debug_func, EsiLib::ComponentBase::Error error_func, HttpDataFetcher &fetcher, 50 EsiLib::Variables &variables, const EsiLib::HandlerManager &handler_mgr); 51 52 /** Initializes the processor with the context of the request to be processed */ 53 bool start(); 54 55 /** Adds data to be parsed */ 56 bool addParseData(const char *data, int data_len = -1); 57 58 /** convenient alternative to method above */ 59 bool addParseData(const std::string & data)60 addParseData(const std::string &data) 61 { 62 return addParseData(data.data(), data.size()); 63 } 64 65 /** Tells processor to wrap-up parsing; a final or the only piece of 66 * data can be optionally provided */ 67 bool completeParse(const char *data = nullptr, int data_len = -1); 68 69 /** convenient alternative to method above */ 70 bool completeParse(const std::string & data)71 completeParse(const std::string &data) 72 { 73 return completeParse(data.data(), data.size()); 74 } 75 76 enum ReturnCode { 77 FAILURE, 78 SUCCESS, 79 NEED_MORE_DATA, 80 }; 81 82 /** Processes the currently parsed ESI document and returns processed 83 * data in supplied out-parameters. Should be called when fetcher has 84 * finished pulling in all data. 85 * 86 * try/attempt/except construct can generate new fetch requests 87 * during processing. Only in such cases is NEED_MORE_DATA returned; 88 * else FAILURE/SUCCESS is returned. */ 89 ReturnCode process(const char *&data, int &data_len); 90 91 /** Process the ESI document and flush processed data as much as 92 * possible. Can be called when fetcher hasn't finished pulling 93 * in all data. */ 94 ReturnCode flush(std::string &data, int &overall_len); 95 96 /** returns packed version of document currently being processed */ 97 void packNodeList(std::string & buffer,bool retain_buffer_data)98 packNodeList(std::string &buffer, bool retain_buffer_data) 99 { 100 return _node_list.pack(buffer, retain_buffer_data); 101 } 102 103 /** Unpacks previously parsed and packed ESI node list from given 104 * buffer and preps for process(); Unpacked document will point to 105 * data in argument (i.e., caller space) */ 106 UsePackedNodeResult usePackedNodeList(const char *data, int data_len); 107 108 /** convenient alternative to method above */ 109 inline UsePackedNodeResult usePackedNodeList(const std::string & data)110 usePackedNodeList(const std::string &data) 111 { 112 return usePackedNodeList(data.data(), data.size()); 113 } 114 115 /** Clears state from current request */ 116 void stop(); 117 118 virtual ~EsiProcessor(); 119 120 private: 121 enum EXEC_STATE { 122 STOPPED, 123 PARSING, 124 WAITING_TO_PROCESS, 125 PROCESSED, 126 ERRORED, 127 }; 128 EXEC_STATE _curr_state; 129 130 std::string _output_data; 131 132 EsiParser _parser; 133 EsiLib::DocNodeList _node_list; 134 int _n_prescanned_nodes; 135 int _n_processed_nodes; 136 int _n_processed_try_nodes; 137 int _overall_len; 138 139 HttpDataFetcher &_fetcher; 140 EsiLib::StringHash _include_urls; 141 142 bool _usePackedNodeList; 143 144 bool _processEsiNode(const EsiLib::DocNodeList::iterator &iter); 145 bool _handleParseComplete(); 146 bool _getIncludeData(const EsiLib::DocNode &node, const char **content_ptr = nullptr, int *content_len_ptr = nullptr); 147 DataStatus _getIncludeStatus(const EsiLib::DocNode &node); 148 bool _handleVars(const char *str, int str_len); 149 bool _handleChoose(EsiLib::DocNodeList::iterator &curr_node); 150 bool _handleTry(EsiLib::DocNodeList::iterator &curr_node); 151 bool _handleHtmlComment(const EsiLib::DocNodeList::iterator &curr_node); 152 bool _preprocess(EsiLib::DocNodeList &node_list, int &n_prescanned_nodes); 153 inline bool _isWhitespace(const char *data, int data_len); 154 void _addFooterData(); 155 156 EsiLib::Variables &_esi_vars; 157 EsiLib::Expression _expression; 158 159 struct TryBlock { 160 EsiLib::DocNodeList &attempt_nodes; 161 EsiLib::DocNodeList &except_nodes; 162 EsiLib::DocNodeList::iterator pos; TryBlockTryBlock163 TryBlock(EsiLib::DocNodeList &att, EsiLib::DocNodeList &exc, EsiLib::DocNodeList::iterator p) 164 : attempt_nodes(att), except_nodes(exc), pos(p){}; 165 }; 166 typedef std::list<TryBlock> TryBlockList; 167 TryBlockList _try_blocks; 168 int _n_try_blocks_processed; 169 170 const EsiLib::HandlerManager &_handler_manager; 171 172 static const char *INCLUDE_DATA_ID_ATTR; 173 174 typedef std::map<std::string, EsiLib::SpecialIncludeHandler *> IncludeHandlerMap; 175 IncludeHandlerMap _include_handlers; 176 177 void error()178 error() 179 { 180 stop(); 181 _curr_state = ERRORED; 182 } 183 }; 184