2 * Copyright (C) 1996-2014 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 86 ESI processing */
13 #include "esi/CustomParser.h"
15 #include "libTrie/Trie.h"
16 #include "libTrie/TrieCharTransform.h"
20 Trie
*ESICustomParser::SearchTrie
=NULL
;
22 EsiParserDefinition(ESICustomParser
);
25 ESICustomParser::GetTrie()
30 SearchTrie
= new Trie(new TrieCaseless
);
32 static const ESITAG_t ESITAG_value
= ESITAG
;
34 assert (SearchTrie
->add
35 ("<esi:",5,(void *)&ESITAG_value
));
37 static const ESITAG_t ESIENDTAG_value
= ESIENDTAG
;
39 assert (SearchTrie
->add
40 ("</esi:",6,(void *)&ESIENDTAG_value
));
42 static const ESITAG_t ESICOMMENT_value
= ESICOMMENT
;
44 assert (SearchTrie
->add
45 ("<!--",4,(void *)&ESICOMMENT_value
));
50 ESICustomParser::ESICustomParser(ESIParserClient
*aClient
) :
55 ESICustomParser::~ESICustomParser()
61 ESICustomParser::findTag(char const *buffer
, size_t bufferLength
)
64 ESITAG_t
*resulttype
= NULL
;
66 while (myOffset
< bufferLength
&&
67 (resulttype
= static_cast<ESITAG_t
*>(GetTrie()->findPrefix (buffer
+ myOffset
, bufferLength
- myOffset
)))
71 if (myOffset
== bufferLength
)
74 debugs(86, 9, "ESICustomParser::findTag: found " << *resulttype
);
76 lastTag
= *resulttype
;
78 return buffer
+ myOffset
;
82 ESICustomParser::parse(char const *dataToParse
, size_t const lengthOfData
, bool const endOfStream
)
84 debugs(86, 9, "ESICustomParser::parse: Appending data to internal buffer");
85 content
.append (dataToParse
, lengthOfData
);
91 size_t openESITags (0);
92 //erring on the safe side. Probably rawBuf would be ok too
93 char const *currentPos
= content
.termedBuf();
94 size_t remainingCount
= content
.size();
95 char const *tag
= NULL
;
97 while ((tag
= findTag(currentPos
, remainingCount
))) {
99 theClient
->parserDefault (currentPos
,tag
- currentPos
);
105 char *tagEnd
= strchr(const_cast<char *>(tag
), '>');
108 error
= "Could not find end ('>') of tag";
112 if (tagEnd
- tag
> (ssize_t
)remainingCount
) {
113 error
= "Tag ends beyond the parse buffer.";
117 if (*(tagEnd
- 1) == '/')
120 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
122 if (endofName
> tagEnd
)
123 endofName
= const_cast<char *>(tagEnd
);
129 std::vector
<char *>attributes
;
131 char *attribute
= const_cast<char *>(endofName
+ 1);
133 while (attribute
> tag
&& attribute
< tagEnd
) {
136 while (attribute
< tagEnd
&& (xisspace(*attribute
) || (*attribute
== '/')))
139 if (! (attribute
< tagEnd
))
143 attributes
.push_back(attribute
);
145 char *nextSpace
= strpbrk(attribute
, w_space
);
147 char *equals
= strchr(attribute
, '=');
150 error
= "Missing attribute value.";
154 if (nextSpace
&& nextSpace
< equals
)
161 while (equals
< tagEnd
&& xisspace(*equals
))
166 if (sep
!= '\'' && sep
!= '"') {
167 error
= "Unknown identifier (";
173 char *value
= equals
+ 1;
174 char *end
= strchr(value
, sep
);
177 error
= "Missing attribute ending separator (";
182 attributes
.push_back(value
);
187 // TODO: after c++11, replace &attributes.front() with attributes.data()
188 theClient
->start (tag
+ 1, const_cast<const char **>(&attributes
.front()), attributes
.size() >> 1);
189 /* TODO: attributes */
191 if (*(tagEnd
- 1) == '/')
192 theClient
->end (tag
+ 1);
194 remainingCount
-= tagEnd
- currentPos
+ 1;
196 currentPos
= tagEnd
+ 1;
205 char const *tagEnd
= strchr(tag
, '>');
210 if (tagEnd
- tag
> (ssize_t
)remainingCount
)
213 char * endofName
= strpbrk(const_cast<char *>(tag
), w_space
);
215 if (endofName
> tagEnd
)
216 endofName
= const_cast<char *>(tagEnd
);
220 theClient
->end (tag
+ 2);
224 remainingCount
-= tagEnd
- currentPos
+ 1;
226 currentPos
= tagEnd
+ 1;
232 /* Further optimisation potential:
233 * 1) recognize end comments for esi and don't callback on
235 * 2) provide the comment length to the caller.
237 /* Comments must not be nested, without CDATA
238 * and we don't support CDATA
240 char *commentEnd
= strstr (const_cast<char *>(tag
), "-->");
243 error
= "missing end of comment";
247 if (commentEnd
- tag
> (ssize_t
)remainingCount
) {
248 error
= "comment ends beyond parse buffer";
253 theClient
->parserComment (tag
+ 4);
254 remainingCount
-= commentEnd
- currentPos
+ 3;
255 currentPos
= commentEnd
+ 3;
262 fatal ("unknown ESI tag type found");
266 * Find next esi tag (open or closing) or comment
267 * send tag, or full comment text
273 theClient
->parserDefault (currentPos
,remainingCount
);
275 debugs(86, 5, "ESICustomParser::parse: Finished parsing, will return " << !openESITags
);
278 error
= "ESI Tags still open";
284 ESICustomParser::lineNumber() const
286 /* We don't track lines in the body */
291 ESICustomParser::errorString() const
294 return error
.termedBuf();
296 return "Parsing error strings not implemented";