3 * DEBUG: section 86 ESI processing
4 * AUTHOR: Robert Collins
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful,
24 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
35 #include "base/Vector.h"
37 #include "esi/CustomParser.h"
38 #include "libTrie/Trie.h"
39 #include "libTrie/TrieCharTransform.h"
41 Trie
*ESICustomParser::SearchTrie
=NULL
;
43 EsiParserDefinition(ESICustomParser
);
46 ESICustomParser::GetTrie()
51 SearchTrie
= new Trie(new TrieCaseless
);
53 static const ESITAG_t ESITAG_value
= ESITAG
;
55 assert (SearchTrie
->add
56 ("<esi:",5,(void *)&ESITAG_value
));
58 static const ESITAG_t ESIENDTAG_value
= ESIENDTAG
;
60 assert (SearchTrie
->add
61 ("</esi:",6,(void *)&ESIENDTAG_value
));
63 static const ESITAG_t ESICOMMENT_value
= ESICOMMENT
;
65 assert (SearchTrie
->add
66 ("<!--",4,(void *)&ESICOMMENT_value
));
71 ESICustomParser::ESICustomParser(ESIParserClient
*aClient
) :
76 ESICustomParser::~ESICustomParser()
82 ESICustomParser::findTag(char const *buffer
, size_t bufferLength
)
85 ESITAG_t
*resulttype
= NULL
;
87 while (myOffset
< bufferLength
&&
88 (resulttype
= static_cast<ESITAG_t
*>(GetTrie()->findPrefix (buffer
+ myOffset
, bufferLength
- myOffset
)))
92 if (myOffset
== bufferLength
)
95 debugs(86, 9, "ESICustomParser::findTag: found " << *resulttype
);
97 lastTag
= *resulttype
;
99 return buffer
+ myOffset
;
103 ESICustomParser::parse(char const *dataToParse
, size_t const lengthOfData
, bool const endOfStream
)
105 debugs(86, 9, "ESICustomParser::parse: Appending data to internal buffer");
106 content
.append (dataToParse
, lengthOfData
);
112 size_t openESITags (0);
113 //erring on the safe side. Probably rawBuf would be ok too
114 char const *currentPos
= content
.termedBuf();
115 size_t remainingCount
= content
.size();
116 char const *tag
= NULL
;
118 while ((tag
= findTag(currentPos
, remainingCount
))) {
119 if (tag
- currentPos
)
120 theClient
->parserDefault (currentPos
,tag
- currentPos
);
126 char *tagEnd
= strchr(const_cast<char *>(tag
), '>');
129 error
= "Could not find end ('>') of tag";
133 if (tagEnd
- tag
> (ssize_t
)remainingCount
) {
134 error
= "Tag ends beyond the parse buffer.";
138 if (*(tagEnd
- 1) == '/')
141 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
143 if (endofName
> tagEnd
)
144 endofName
= const_cast<char *>(tagEnd
);
150 Vector
<char *>attributes
;
152 char *attribute
= const_cast<char *>(endofName
+ 1);
154 while (attribute
> tag
&& attribute
< tagEnd
) {
157 while (attribute
< tagEnd
&& (xisspace(*attribute
) || (*attribute
== '/')))
160 if (! (attribute
< tagEnd
))
164 attributes
.push_back(attribute
);
166 char *nextSpace
= strpbrk(attribute
, w_space
);
168 char *equals
= strchr(attribute
, '=');
171 error
= "Missing attribute value.";
175 if (nextSpace
&& nextSpace
< equals
)
182 while (equals
< tagEnd
&& xisspace(*equals
))
187 if (sep
!= '\'' && sep
!= '"') {
188 error
= "Unknown identifier (";
194 char *value
= equals
+ 1;
195 char *end
= strchr(value
, sep
);
198 error
= "Missing attribute ending separator (";
203 attributes
.push_back(value
);
208 theClient
->start (tag
+ 1, (const char **)attributes
.items
, attributes
.size() >> 1);
209 /* TODO: attributes */
211 if (*(tagEnd
- 1) == '/')
212 theClient
->end (tag
+ 1);
214 remainingCount
-= tagEnd
- currentPos
+ 1;
216 currentPos
= tagEnd
+ 1;
225 char const *tagEnd
= strchr(tag
, '>');
230 if (tagEnd
- tag
> (ssize_t
)remainingCount
)
233 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
235 if (endofName
> tagEnd
)
236 endofName
= const_cast<char *>(tagEnd
);
240 theClient
->end (tag
+ 2);
244 remainingCount
-= tagEnd
- currentPos
+ 1;
246 currentPos
= tagEnd
+ 1;
252 /* Further optimisation potential:
253 * 1) recognize end comments for esi and don't callback on
255 * 2) provide the comment length to the caller.
257 /* Comments must not be nested, without CDATA
258 * and we don't support CDATA
260 char *commentEnd
= strstr (const_cast<char *>(tag
), "-->");
263 error
= "missing end of comment";
267 if (commentEnd
- tag
> (ssize_t
)remainingCount
) {
268 error
= "comment ends beyond parse buffer";
273 theClient
->parserComment (tag
+ 4);
274 remainingCount
-= commentEnd
- currentPos
+ 3;
275 currentPos
= commentEnd
+ 3;
282 fatal ("unknown ESI tag type found");
286 * Find next esi tag (open or closing) or comment
287 * send tag, or full comment text
293 theClient
->parserDefault (currentPos
,remainingCount
);
295 debugs(86, 5, "ESICustomParser::parse: Finished parsing, will return " << !openESITags
);
298 error
= "ESI Tags still open";
304 ESICustomParser::lineNumber() const
306 /* We don't track lines in the body */
311 ESICustomParser::errorString() const
314 return error
.termedBuf();
316 return "Parsing error strings not implemented";