]> git.ipfire.org Git - thirdparty/squid.git/blame - src/ESICustomParser.cc
Summary: Merge ESI to HEAD.
[thirdparty/squid.git] / src / ESICustomParser.cc
CommitLineData
43ae1d95 1
2/*
3 * $Id: ESICustomParser.cc,v 1.1 2003/03/10 04:56:35 robertc Exp $
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"
39#include "Array.h"
40
41Trie *ESICustomParser::SearchTrie=NULL;
42bool ESICustomParser::TrieInited;
43
44Trie *
45ESICustomParser::GetTrie()
46{
47 if (SearchTrie)
48 return SearchTrie;
49
50 SearchTrie = new Trie;
51
52 assert (SearchTrie->add
53 ("<esi:",5,(void *)ESITAG));
54
55 assert (SearchTrie->add
56 ("</esi:",6,(void *)ESIENDTAG));
57
58 assert (SearchTrie->add
59 ("<!--",4,(void *)ESICOMMENT));
60
61 return SearchTrie;
62}
63
64void
65ESICustomParser::deleteSelf() const
66{
67 delete this;
68}
69
70ESICustomParser::ESICustomParser(ESIParserClient *aClient) : theClient (aClient)
71{}
72
73ESICustomParser::~ESICustomParser()
74{
75 theClient = NULL;
76}
77
78char const *
79ESICustomParser::findTag(char const *a, size_t b)
80{
81 size_t myOffset (0);
82 void *resulttype (NULL);
83
84 while (myOffset < b &&
85 (resulttype =GetTrie()->findPrefix (a + myOffset, b + myOffset)) == NULL)
86 ++myOffset;
87
88 if (myOffset == b)
89 return NULL;
90
91 debug (86,9)("ESICustomParser::findTag: found %p\n", resulttype);
92
93 /* Yuck! */
94 lastTag = static_cast<ESITAG_t>((int)resulttype);
95
96 return a + myOffset;
97}
98
99bool
100ESICustomParser::parse(char const *dataToParse, size_t const lengthOfData, bool const endOfStream)
101{
102 debug (86,9)("ESICustomParser::parse: Appending data to internal buffer\n");
103 content.append (dataToParse, lengthOfData);
104
105 if (!endOfStream) {
106 return true;
107 }
108
109 size_t openESITags (0);
110 char const *currentPos = content.buf();
111 size_t remainingCount = content.size();
112 char const *tag (NULL);
113
114 while ((tag = findTag(currentPos, remainingCount))) {
115 if (tag - currentPos)
116 theClient->parserDefault (currentPos,tag - currentPos);
117
118 switch (lastTag) {
119
120 case ESITAG: {
121 ++openESITags;
122 char *tagEnd = strchr(tag, '>');
123
124 if (!tagEnd) {
125 error = "Could not find end ('>') of tag";
126 return false;
127 }
128
129 if (tagEnd - tag > (ssize_t)remainingCount) {
130 error = "Tag ends beyond the parse buffer.";
131 return false;
132 }
133
134 if (*(tagEnd - 1) == '/')
135 --openESITags;
136
137 char * endofName = strpbrk(tag, w_space);
138
139 if (endofName > tagEnd)
140 endofName = const_cast<char *>(tagEnd);
141
142 *endofName = '\0';
143
144 *tagEnd = '\0';
145
146 Vector<char *>attributes;
147
148 char *attribute = endofName + 1;
149
150 while (attribute > tag && attribute < tagEnd) {
151 /* leading spaces */
152
153 while (attribute < tagEnd && (xisspace(*attribute) || (*attribute == '/')))
154 ++attribute;
155
156 if (! (attribute < tagEnd))
157 break;
158
159 /* attribute name */
160 attributes.push_back(attribute);
161
162 char *nextSpace = strpbrk(attribute, w_space);
163
164 char *equals = strchr(attribute, '=');
165
166 if (!equals) {
167 error = "Missing attribute value.";
168 return false;
169 }
170
171 if (nextSpace && nextSpace < equals)
172 *nextSpace = '\0';
173 else
174 *equals = '\0';
175
176 ++equals;
177
178 while (equals < tagEnd && xisspace(*equals))
179 ++equals;
180
181 char sep = *equals;
182
183 if (sep != '\'' && sep != '"') {
184 error = "Unknown identifier (";
185 error.append (sep);
186 error.append (")");
187 return false;
188 }
189
190 char *value = equals + 1;
191 char *end = strchr (value, sep);
192 attributes.push_back(value);
193 *end = '\0';
194 attribute = end + 1;
195 }
196
197 theClient->start (tag + 1, (const char **)attributes.items, attributes.size() >> 1);
198 /* TODO: attributes */
199
200 if (*(tagEnd - 1) == '/')
201 theClient->end (tag + 1);
202
203 remainingCount -= tagEnd - currentPos + 1;
204
205 currentPos = tagEnd + 1;
206 }
207
208 break;
209
210 case ESIENDTAG: {
211 if (!openESITags)
212 return false;
213
214 char const *tagEnd = strchr(tag, '>');
215
216 if (!tagEnd)
217 return false;
218
219 if (tagEnd - tag > (ssize_t)remainingCount)
220 return false;
221
222 char * endofName = strpbrk(tag, w_space);
223
224 if (endofName > tagEnd)
225 endofName = const_cast<char *>(tagEnd);
226
227 *endofName = '\0';
228
229 theClient->end (tag + 2);
230
231 --openESITags;
232
233 remainingCount -= tagEnd - currentPos + 1;
234
235 currentPos = tagEnd + 1;
236 }
237
238 break;
239
240 case ESICOMMENT: {
241 /* Further optimisation potential:
242 * 1) recognize end comments for esi and don't callback on
243 * comments.
244 * 2) provide the comment length to the caller.
245 */
246 /* Comments must not be nested, without CDATA
247 * and we don't support CDATA
248 */
249 char *commentEnd = strstr (tag, "-->");
250
251 if (!commentEnd) {
252 error = "missing end of comment";
253 return false;
254 }
255
256 if (commentEnd - tag > (ssize_t)remainingCount) {
257 error = "comment ends beyond parse buffer";
258 return false;
259 }
260
261 *commentEnd = '\0';
262 theClient->parserComment (tag + 4);
263 remainingCount -= commentEnd - currentPos + 3;
264 currentPos = commentEnd + 3;
265 }
266
267 break;
268 break;
269
270 default:
271 fatal ("unknown ESI tag type found");
272 };
273
274 /*
275 * Find next esi tag (open or closing) or comment
276 * send tag, or full comment text
277 * rinse
278 */
279 }
280
281 if (remainingCount)
282 theClient->parserDefault (currentPos,remainingCount);
283
284 debug (86,5)("ESICustomParser::parse: Finished parsing, will return %d\n", !openESITags);
285
286 if (openESITags)
287 error = "ESI Tags still open";
288
289 return !openESITags;
290}
291
292size_t
293ESICustomParser::lineNumber() const
294{
295 /* We don't track lines in the body */
296 return 0;
297}
298
299char const *
300ESICustomParser::errorString() const
301{
302 if (error.size())
303 return error.buf();
304 else
305 return "Parsing error strings not implemented";
306}