]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ESICustomParser.cc
Adding a comment that tests/testUfs will fail when 'heap' is the only
[thirdparty/squid.git] / src / ESICustomParser.cc
CommitLineData
43ae1d95 1
2/*
137a13ea 3 * $Id: ESICustomParser.cc,v 1.7 2005/07/03 15:25:08 serassio Exp $
43ae1d95 4 *
5 * DEBUG: section 86 ESI processing
6 * AUTHOR: Robert Collins
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36#include "squid.h"
37#include "ESICustomParser.h"
38#include "Trie.h"
924f73bc 39#include "TrieCharTransform.h"
43ae1d95 40#include "Array.h"
41
42Trie *ESICustomParser::SearchTrie=NULL;
43ae1d95 43
c2d4889f 44RegisterESIParser("custom", ESICustomParser);
45
43ae1d95 46Trie *
47ESICustomParser::GetTrie()
48{
49 if (SearchTrie)
50 return SearchTrie;
51
924f73bc 52 SearchTrie = new Trie(new TrieCaseless);
43ae1d95 53
137a13ea 54 static const ESITAG_t ESITAG_value = ESITAG;
55
43ae1d95 56 assert (SearchTrie->add
137a13ea 57 ("<esi:",5,(void *)&ESITAG_value));
58
59 static const ESITAG_t ESIENDTAG_value = ESIENDTAG;
43ae1d95 60
61 assert (SearchTrie->add
137a13ea 62 ("</esi:",6,(void *)&ESIENDTAG_value));
63
64 static const ESITAG_t ESICOMMENT_value = ESICOMMENT;
43ae1d95 65
66 assert (SearchTrie->add
137a13ea 67 ("<!--",4,(void *)&ESICOMMENT_value));
43ae1d95 68
69 return SearchTrie;
70}
71
43ae1d95 72ESICustomParser::ESICustomParser(ESIParserClient *aClient) : theClient (aClient)
73{}
74
75ESICustomParser::~ESICustomParser()
76{
77 theClient = NULL;
78}
79
80char const *
924f73bc 81ESICustomParser::findTag(char const *buffer, size_t bufferLength)
43ae1d95 82{
83 size_t myOffset (0);
137a13ea 84 ESITAG_t *resulttype = NULL;
43ae1d95 85
924f73bc 86 while (myOffset < bufferLength &&
137a13ea 87 (resulttype = static_cast<ESITAG_t *>(GetTrie()->findPrefix (buffer + myOffset, bufferLength - myOffset)))
88 == NULL)
43ae1d95 89 ++myOffset;
90
924f73bc 91 if (myOffset == bufferLength)
43ae1d95 92 return NULL;
93
137a13ea 94 debug (86,9)("ESICustomParser::findTag: found %d\n", *resulttype);
43ae1d95 95
137a13ea 96 lastTag = *resulttype;
43ae1d95 97
924f73bc 98 return buffer + myOffset;
43ae1d95 99}
100
101bool
102ESICustomParser::parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream)
103{
104 debug (86,9)("ESICustomParser::parse: Appending data to internal buffer\n");
105 content.append (dataToParse, lengthOfData);
106
107 if (!endOfStream) {
108 return true;
109 }
110
111 size_t openESITags (0);
112 char const *currentPos = content.buf();
113 size_t remainingCount = content.size();
5aeabf95 114 char const *tag = NULL;
43ae1d95 115
116 while ((tag = findTag(currentPos, remainingCount))) {
117 if (tag - currentPos)
118 theClient->parserDefault (currentPos,tag - currentPos);
119
120 switch (lastTag) {
121
122 case ESITAG: {
123 ++openESITags;
411c6ea3 124 char *tagEnd = strchr(const_cast<char *>(tag), '>');
43ae1d95 125
126 if (!tagEnd) {
127 error = "Could not find end ('>') of tag";
128 return false;
129 }
130
131 if (tagEnd - tag > (ssize_t)remainingCount) {
132 error = "Tag ends beyond the parse buffer.";
133 return false;
134 }
135
136 if (*(tagEnd - 1) == '/')
137 --openESITags;
138
411c6ea3 139 char * endofName = strpbrk(const_cast<char *>(tag), w_space);
43ae1d95 140
141 if (endofName > tagEnd)
142 endofName = const_cast<char *>(tagEnd);
143
144 *endofName = '\0';
145
146 *tagEnd = '\0';
147
148 Vector<char *>attributes;
149
411c6ea3 150 char *attribute = const_cast<char *>(endofName + 1);
43ae1d95 151
152 while (attribute > tag && attribute < tagEnd) {
153 /* leading spaces */
154
155 while (attribute < tagEnd && (xisspace(*attribute) || (*attribute == '/')))
156 ++attribute;
157
158 if (! (attribute < tagEnd))
159 break;
160
161 /* attribute name */
162 attributes.push_back(attribute);
163
164 char *nextSpace = strpbrk(attribute, w_space);
165
166 char *equals = strchr(attribute, '=');
167
168 if (!equals) {
169 error = "Missing attribute value.";
170 return false;
171 }
172
173 if (nextSpace && nextSpace < equals)
174 *nextSpace = '\0';
175 else
176 *equals = '\0';
177
178 ++equals;
179
180 while (equals < tagEnd && xisspace(*equals))
181 ++equals;
182
183 char sep = *equals;
184
185 if (sep != '\'' && sep != '"') {
186 error = "Unknown identifier (";
187 error.append (sep);
188 error.append (")");
189 return false;
190 }
191
192 char *value = equals + 1;
193 char *end = strchr (value, sep);
194 attributes.push_back(value);
195 *end = '\0';
196 attribute = end + 1;
197 }
198
199 theClient->start (tag + 1, (const char **)attributes.items, attributes.size() >> 1);
200 /* TODO: attributes */
201
202 if (*(tagEnd - 1) == '/')
203 theClient->end (tag + 1);
204
205 remainingCount -= tagEnd - currentPos + 1;
206
207 currentPos = tagEnd + 1;
208 }
209
210 break;
211
212 case ESIENDTAG: {
213 if (!openESITags)
214 return false;
215
216 char const *tagEnd = strchr(tag, '>');
217
218 if (!tagEnd)
219 return false;
220
221 if (tagEnd - tag > (ssize_t)remainingCount)
222 return false;
223
411c6ea3 224 char * endofName = strpbrk(const_cast<char *>(tag), w_space);
43ae1d95 225
226 if (endofName > tagEnd)
227 endofName = const_cast<char *>(tagEnd);
228
229 *endofName = '\0';
230
231 theClient->end (tag + 2);
232
233 --openESITags;
234
235 remainingCount -= tagEnd - currentPos + 1;
236
237 currentPos = tagEnd + 1;
238 }
239
240 break;
241
242 case ESICOMMENT: {
243 /* Further optimisation potential:
244 * 1) recognize end comments for esi and don't callback on
245 * comments.
246 * 2) provide the comment length to the caller.
247 */
248 /* Comments must not be nested, without CDATA
249 * and we don't support CDATA
250 */
411c6ea3 251 char *commentEnd = strstr (const_cast<char *>(tag), "-->");
43ae1d95 252
253 if (!commentEnd) {
254 error = "missing end of comment";
255 return false;
256 }
257
258 if (commentEnd - tag > (ssize_t)remainingCount) {
259 error = "comment ends beyond parse buffer";
260 return false;
261 }
262
263 *commentEnd = '\0';
264 theClient->parserComment (tag + 4);
265 remainingCount -= commentEnd - currentPos + 3;
266 currentPos = commentEnd + 3;
267 }
268
269 break;
270 break;
271
272 default:
273 fatal ("unknown ESI tag type found");
274 };
275
276 /*
277 * Find next esi tag (open or closing) or comment
278 * send tag, or full comment text
279 * rinse
280 */
281 }
282
283 if (remainingCount)
284 theClient->parserDefault (currentPos,remainingCount);
285
286 debug (86,5)("ESICustomParser::parse: Finished parsing, will return %d\n", !openESITags);
287
288 if (openESITags)
289 error = "ESI Tags still open";
290
291 return !openESITags;
292}
293
137a13ea 294long int
43ae1d95 295ESICustomParser::lineNumber() const
296{
297 /* We don't track lines in the body */
298 return 0;
299}
300
301char const *
302ESICustomParser::errorString() const
303{
304 if (error.size())
305 return error.buf();
306 else
307 return "Parsing error strings not implemented";
308}