5 * DEBUG: section 86 ESI processing
6 * AUTHOR: Robert Collins
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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.
37 #include "ESICustomParser.h"
39 #include "TrieCharTransform.h"
42 Trie
*ESICustomParser::SearchTrie
=NULL
;
44 RegisterESIParser("custom", ESICustomParser
);
47 ESICustomParser::GetTrie()
52 SearchTrie
= new Trie(new TrieCaseless
);
54 static const ESITAG_t ESITAG_value
= ESITAG
;
56 assert (SearchTrie
->add
57 ("<esi:",5,(void *)&ESITAG_value
));
59 static const ESITAG_t ESIENDTAG_value
= ESIENDTAG
;
61 assert (SearchTrie
->add
62 ("</esi:",6,(void *)&ESIENDTAG_value
));
64 static const ESITAG_t ESICOMMENT_value
= ESICOMMENT
;
66 assert (SearchTrie
->add
67 ("<!--",4,(void *)&ESICOMMENT_value
));
72 ESICustomParser::ESICustomParser(ESIParserClient
*aClient
) : theClient (aClient
)
75 ESICustomParser::~ESICustomParser()
81 ESICustomParser::findTag(char const *buffer
, size_t bufferLength
)
84 ESITAG_t
*resulttype
= NULL
;
86 while (myOffset
< bufferLength
&&
87 (resulttype
= static_cast<ESITAG_t
*>(GetTrie()->findPrefix (buffer
+ myOffset
, bufferLength
- myOffset
)))
91 if (myOffset
== bufferLength
)
94 debugs(86, 9, "ESICustomParser::findTag: found " << *resulttype
);
96 lastTag
= *resulttype
;
98 return buffer
+ myOffset
;
102 ESICustomParser::parse(char const *dataToParse
, size_t const lengthOfData
, bool const endOfStream
)
104 debugs(86, 9, "ESICustomParser::parse: Appending data to internal buffer");
105 content
.append (dataToParse
, lengthOfData
);
111 size_t openESITags (0);
112 //erring on the safe side. Probably rawBuf would be ok too
113 char const *currentPos
= content
.termedBuf();
114 size_t remainingCount
= content
.size();
115 char const *tag
= NULL
;
117 while ((tag
= findTag(currentPos
, remainingCount
))) {
118 if (tag
- currentPos
)
119 theClient
->parserDefault (currentPos
,tag
- currentPos
);
125 char *tagEnd
= strchr(const_cast<char *>(tag
), '>');
128 error
= "Could not find end ('>') of tag";
132 if (tagEnd
- tag
> (ssize_t
)remainingCount
) {
133 error
= "Tag ends beyond the parse buffer.";
137 if (*(tagEnd
- 1) == '/')
140 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
142 if (endofName
> tagEnd
)
143 endofName
= const_cast<char *>(tagEnd
);
149 Vector
<char *>attributes
;
151 char *attribute
= const_cast<char *>(endofName
+ 1);
153 while (attribute
> tag
&& attribute
< tagEnd
) {
156 while (attribute
< tagEnd
&& (xisspace(*attribute
) || (*attribute
== '/')))
159 if (! (attribute
< tagEnd
))
163 attributes
.push_back(attribute
);
165 char *nextSpace
= strpbrk(attribute
, w_space
);
167 char *equals
= strchr(attribute
, '=');
170 error
= "Missing attribute value.";
174 if (nextSpace
&& nextSpace
< equals
)
181 while (equals
< tagEnd
&& xisspace(*equals
))
186 if (sep
!= '\'' && sep
!= '"') {
187 error
= "Unknown identifier (";
193 char *value
= equals
+ 1;
194 char *end
= strchr (value
, sep
);
195 attributes
.push_back(value
);
200 theClient
->start (tag
+ 1, (const char **)attributes
.items
, attributes
.size() >> 1);
201 /* TODO: attributes */
203 if (*(tagEnd
- 1) == '/')
204 theClient
->end (tag
+ 1);
206 remainingCount
-= tagEnd
- currentPos
+ 1;
208 currentPos
= tagEnd
+ 1;
217 char const *tagEnd
= strchr(tag
, '>');
222 if (tagEnd
- tag
> (ssize_t
)remainingCount
)
225 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
227 if (endofName
> tagEnd
)
228 endofName
= const_cast<char *>(tagEnd
);
232 theClient
->end (tag
+ 2);
236 remainingCount
-= tagEnd
- currentPos
+ 1;
238 currentPos
= tagEnd
+ 1;
244 /* Further optimisation potential:
245 * 1) recognize end comments for esi and don't callback on
247 * 2) provide the comment length to the caller.
249 /* Comments must not be nested, without CDATA
250 * and we don't support CDATA
252 char *commentEnd
= strstr (const_cast<char *>(tag
), "-->");
255 error
= "missing end of comment";
259 if (commentEnd
- tag
> (ssize_t
)remainingCount
) {
260 error
= "comment ends beyond parse buffer";
265 theClient
->parserComment (tag
+ 4);
266 remainingCount
-= commentEnd
- currentPos
+ 3;
267 currentPos
= commentEnd
+ 3;
274 fatal ("unknown ESI tag type found");
278 * Find next esi tag (open or closing) or comment
279 * send tag, or full comment text
285 theClient
->parserDefault (currentPos
,remainingCount
);
287 debugs(86, 5, "ESICustomParser::parse: Finished parsing, will return " << !openESITags
);
290 error
= "ESI Tags still open";
296 ESICustomParser::lineNumber() const
298 /* We don't track lines in the body */
303 ESICustomParser::errorString() const
306 return error
.termedBuf();
308 return "Parsing error strings not implemented";