]> git.ipfire.org Git - thirdparty/squid.git/blame - src/esi/CustomParser.cc
Renamed squid.h to squid-old.h and config.h to squid.h
[thirdparty/squid.git] / src / esi / CustomParser.cc
CommitLineData
43ae1d95 1
2/*
262a0e14 3 * $Id$
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.
26ac0430 24 *
43ae1d95 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.
26ac0430 29 *
43ae1d95 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
f7f3304a 36#include "squid-old.h"
f99c2cfe 37#include "esi/CustomParser.h"
43ae1d95 38#include "Trie.h"
924f73bc 39#include "TrieCharTransform.h"
43ae1d95 40#include "Array.h"
41
42Trie *ESICustomParser::SearchTrie=NULL;
43ae1d95 43
019db3c6 44EsiParserDefinition(ESICustomParser);
c2d4889f 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
bf8fe701 94 debugs(86, 9, "ESICustomParser::findTag: found " << *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{
bf8fe701 104 debugs(86, 9, "ESICustomParser::parse: Appending data to internal buffer");
43ae1d95 105 content.append (dataToParse, lengthOfData);
106
107 if (!endOfStream) {
108 return true;
109 }
110
111 size_t openESITags (0);
a7a42b14
FC
112 //erring on the safe side. Probably rawBuf would be ok too
113 char const *currentPos = content.termedBuf();
43ae1d95 114 size_t remainingCount = content.size();
5aeabf95 115 char const *tag = NULL;
43ae1d95 116
117 while ((tag = findTag(currentPos, remainingCount))) {
118 if (tag - currentPos)
119 theClient->parserDefault (currentPos,tag - currentPos);
120
121 switch (lastTag) {
122
123 case ESITAG: {
26ac0430
AJ
124 ++openESITags;
125 char *tagEnd = strchr(const_cast<char *>(tag), '>');
43ae1d95 126
26ac0430
AJ
127 if (!tagEnd) {
128 error = "Could not find end ('>') of tag";
129 return false;
130 }
43ae1d95 131
26ac0430
AJ
132 if (tagEnd - tag > (ssize_t)remainingCount) {
133 error = "Tag ends beyond the parse buffer.";
134 return false;
135 }
43ae1d95 136
26ac0430
AJ
137 if (*(tagEnd - 1) == '/')
138 --openESITags;
43ae1d95 139
26ac0430 140 char * endofName = strpbrk(const_cast<char *>(tag), w_space);
43ae1d95 141
26ac0430
AJ
142 if (endofName > tagEnd)
143 endofName = const_cast<char *>(tagEnd);
43ae1d95 144
26ac0430 145 *endofName = '\0';
43ae1d95 146
26ac0430 147 *tagEnd = '\0';
43ae1d95 148
26ac0430 149 Vector<char *>attributes;
43ae1d95 150
26ac0430 151 char *attribute = const_cast<char *>(endofName + 1);
43ae1d95 152
26ac0430
AJ
153 while (attribute > tag && attribute < tagEnd) {
154 /* leading spaces */
43ae1d95 155
26ac0430
AJ
156 while (attribute < tagEnd && (xisspace(*attribute) || (*attribute == '/')))
157 ++attribute;
43ae1d95 158
26ac0430
AJ
159 if (! (attribute < tagEnd))
160 break;
43ae1d95 161
26ac0430
AJ
162 /* attribute name */
163 attributes.push_back(attribute);
43ae1d95 164
26ac0430 165 char *nextSpace = strpbrk(attribute, w_space);
43ae1d95 166
26ac0430 167 char *equals = strchr(attribute, '=');
43ae1d95 168
26ac0430
AJ
169 if (!equals) {
170 error = "Missing attribute value.";
171 return false;
172 }
43ae1d95 173
26ac0430
AJ
174 if (nextSpace && nextSpace < equals)
175 *nextSpace = '\0';
176 else
177 *equals = '\0';
43ae1d95 178
26ac0430 179 ++equals;
43ae1d95 180
26ac0430
AJ
181 while (equals < tagEnd && xisspace(*equals))
182 ++equals;
43ae1d95 183
26ac0430 184 char sep = *equals;
43ae1d95 185
26ac0430
AJ
186 if (sep != '\'' && sep != '"') {
187 error = "Unknown identifier (";
188 error.append (sep);
189 error.append (")");
190 return false;
43ae1d95 191 }
192
26ac0430
AJ
193 char *value = equals + 1;
194 char *end = strchr (value, sep);
195 attributes.push_back(value);
196 *end = '\0';
197 attribute = end + 1;
198 }
43ae1d95 199
26ac0430
AJ
200 theClient->start (tag + 1, (const char **)attributes.items, attributes.size() >> 1);
201 /* TODO: attributes */
43ae1d95 202
26ac0430
AJ
203 if (*(tagEnd - 1) == '/')
204 theClient->end (tag + 1);
43ae1d95 205
26ac0430 206 remainingCount -= tagEnd - currentPos + 1;
43ae1d95 207
26ac0430
AJ
208 currentPos = tagEnd + 1;
209 }
210
211 break;
43ae1d95 212
213 case ESIENDTAG: {
26ac0430
AJ
214 if (!openESITags)
215 return false;
43ae1d95 216
26ac0430 217 char const *tagEnd = strchr(tag, '>');
43ae1d95 218
26ac0430
AJ
219 if (!tagEnd)
220 return false;
43ae1d95 221
26ac0430
AJ
222 if (tagEnd - tag > (ssize_t)remainingCount)
223 return false;
43ae1d95 224
26ac0430 225 char * endofName = strpbrk(const_cast<char *>(tag), w_space);
43ae1d95 226
26ac0430
AJ
227 if (endofName > tagEnd)
228 endofName = const_cast<char *>(tagEnd);
43ae1d95 229
26ac0430 230 *endofName = '\0';
43ae1d95 231
26ac0430 232 theClient->end (tag + 2);
43ae1d95 233
26ac0430 234 --openESITags;
43ae1d95 235
26ac0430 236 remainingCount -= tagEnd - currentPos + 1;
43ae1d95 237
26ac0430
AJ
238 currentPos = tagEnd + 1;
239 }
43ae1d95 240
26ac0430 241 break;
43ae1d95 242
243 case ESICOMMENT: {
26ac0430
AJ
244 /* Further optimisation potential:
245 * 1) recognize end comments for esi and don't callback on
246 * comments.
247 * 2) provide the comment length to the caller.
248 */
249 /* Comments must not be nested, without CDATA
250 * and we don't support CDATA
251 */
252 char *commentEnd = strstr (const_cast<char *>(tag), "-->");
253
254 if (!commentEnd) {
255 error = "missing end of comment";
256 return false;
257 }
43ae1d95 258
26ac0430
AJ
259 if (commentEnd - tag > (ssize_t)remainingCount) {
260 error = "comment ends beyond parse buffer";
261 return false;
43ae1d95 262 }
263
26ac0430
AJ
264 *commentEnd = '\0';
265 theClient->parserComment (tag + 4);
266 remainingCount -= commentEnd - currentPos + 3;
267 currentPos = commentEnd + 3;
268 }
269
270 break;
271 break;
43ae1d95 272
273 default:
274 fatal ("unknown ESI tag type found");
275 };
276
277 /*
278 * Find next esi tag (open or closing) or comment
279 * send tag, or full comment text
280 * rinse
281 */
282 }
283
284 if (remainingCount)
285 theClient->parserDefault (currentPos,remainingCount);
286
bf8fe701 287 debugs(86, 5, "ESICustomParser::parse: Finished parsing, will return " << !openESITags);
43ae1d95 288
289 if (openESITags)
290 error = "ESI Tags still open";
291
292 return !openESITags;
293}
294
137a13ea 295long int
43ae1d95 296ESICustomParser::lineNumber() const
297{
298 /* We don't track lines in the body */
299 return 0;
300}
301
302char const *
303ESICustomParser::errorString() const
304{
305 if (error.size())
a7a42b14 306 return error.termedBuf();
43ae1d95 307 else
308 return "Parsing error strings not implemented";
309}