2 * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
20 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 #include "core/html/HTMLViewSourceDocument.h"
28 #include "core/dom/Text.h"
29 #include "core/html/HTMLAnchorElement.h"
30 #include "core/html/HTMLBRElement.h"
31 #include "core/html/HTMLBaseElement.h"
32 #include "core/html/HTMLBodyElement.h"
33 #include "core/html/HTMLDivElement.h"
34 #include "core/html/HTMLHeadElement.h"
35 #include "core/html/HTMLHtmlElement.h"
36 #include "core/html/HTMLSpanElement.h"
37 #include "core/html/HTMLTableCellElement.h"
38 #include "core/html/HTMLTableElement.h"
39 #include "core/html/HTMLTableRowElement.h"
40 #include "core/html/HTMLTableSectionElement.h"
41 #include "core/html/parser/HTMLViewSourceParser.h"
45 using namespace HTMLNames
;
49 const char kXSSDetected
[] = "Token contains a reflected XSS vector";
53 HTMLViewSourceDocument::HTMLViewSourceDocument(const DocumentInit
& initializer
, const String
& mimeType
)
54 : HTMLDocument(initializer
)
57 setIsViewSource(true);
59 // FIXME: Why do view-source pages need to load in quirks mode?
60 setCompatibilityMode(QuirksMode
);
61 lockCompatibilityMode();
64 PassRefPtrWillBeRawPtr
<DocumentParser
> HTMLViewSourceDocument::createParser()
66 return HTMLViewSourceParser::create(*this, m_type
);
69 void HTMLViewSourceDocument::createContainingTable()
71 RefPtrWillBeRawPtr
<HTMLHtmlElement
> html
= HTMLHtmlElement::create(*this);
72 parserAppendChild(html
);
73 RefPtrWillBeRawPtr
<HTMLHeadElement
> head
= HTMLHeadElement::create(*this);
74 html
->parserAppendChild(head
);
75 RefPtrWillBeRawPtr
<HTMLBodyElement
> body
= HTMLBodyElement::create(*this);
76 html
->parserAppendChild(body
);
78 // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole
80 RefPtrWillBeRawPtr
<HTMLDivElement
> div
= HTMLDivElement::create(*this);
81 div
->setAttribute(classAttr
, "line-gutter-backdrop");
82 body
->parserAppendChild(div
);
84 RefPtrWillBeRawPtr
<HTMLTableElement
> table
= HTMLTableElement::create(*this);
85 body
->parserAppendChild(table
);
86 m_tbody
= HTMLTableSectionElement::create(tbodyTag
, *this);
87 table
->parserAppendChild(m_tbody
);
92 void HTMLViewSourceDocument::addSource(const String
& source
, HTMLToken
& token
, SourceAnnotation annotation
)
95 createContainingTable();
97 switch (token
.type()) {
98 case HTMLToken::Uninitialized
:
101 case HTMLToken::DOCTYPE
:
102 processDoctypeToken(source
, token
);
104 case HTMLToken::EndOfFile
:
105 processEndOfFileToken(source
, token
);
107 case HTMLToken::StartTag
:
108 case HTMLToken::EndTag
:
109 processTagToken(source
, token
, annotation
);
111 case HTMLToken::Comment
:
112 processCommentToken(source
, token
);
114 case HTMLToken::Character
:
115 processCharacterToken(source
, token
, annotation
);
120 void HTMLViewSourceDocument::processDoctypeToken(const String
& source
, HTMLToken
&)
122 m_current
= addSpanWithClassName("html-doctype");
123 addText(source
, "html-doctype");
127 void HTMLViewSourceDocument::processEndOfFileToken(const String
& source
, HTMLToken
&)
129 m_current
= addSpanWithClassName("html-end-of-file");
130 addText(source
, "html-end-of-file");
134 void HTMLViewSourceDocument::processTagToken(const String
& source
, HTMLToken
& token
, SourceAnnotation annotation
)
136 maybeAddSpanForAnnotation(annotation
);
137 m_current
= addSpanWithClassName("html-tag");
139 AtomicString
tagName(token
.name());
142 HTMLToken::AttributeList::const_iterator iter
= token
.attributes().begin();
143 while (index
< source
.length()) {
144 if (iter
== token
.attributes().end()) {
145 // We want to show the remaining characters in the token.
146 index
= addRange(source
, index
, source
.length(), emptyAtom
);
147 ASSERT(index
== source
.length());
151 AtomicString
name(iter
->name
);
152 AtomicString
value(StringImpl::create8BitIfPossible(iter
->value
));
154 index
= addRange(source
, index
, iter
->nameRange
.start
- token
.startIndex(), emptyAtom
);
155 index
= addRange(source
, index
, iter
->nameRange
.end
- token
.startIndex(), "html-attribute-name");
157 if (tagName
== baseTag
&& name
== hrefAttr
)
160 index
= addRange(source
, index
, iter
->valueRange
.start
- token
.startIndex(), emptyAtom
);
162 bool isLink
= name
== srcAttr
|| name
== hrefAttr
;
163 index
= addRange(source
, index
, iter
->valueRange
.end
- token
.startIndex(), "html-attribute-value", isLink
, tagName
== aTag
, value
);
170 void HTMLViewSourceDocument::processCommentToken(const String
& source
, HTMLToken
&)
172 m_current
= addSpanWithClassName("html-comment");
173 addText(source
, "html-comment");
177 void HTMLViewSourceDocument::processCharacterToken(const String
& source
, HTMLToken
&, SourceAnnotation annotation
)
179 addText(source
, "", annotation
);
182 PassRefPtrWillBeRawPtr
<Element
> HTMLViewSourceDocument::addSpanWithClassName(const AtomicString
& className
)
184 if (m_current
== m_tbody
) {
189 RefPtrWillBeRawPtr
<HTMLSpanElement
> span
= HTMLSpanElement::create(*this);
190 span
->setAttribute(classAttr
, className
);
191 m_current
->parserAppendChild(span
);
192 return span
.release();
195 void HTMLViewSourceDocument::addLine(const AtomicString
& className
)
197 // Create a table row.
198 RefPtrWillBeRawPtr
<HTMLTableRowElement
> trow
= HTMLTableRowElement::create(*this);
199 m_tbody
->parserAppendChild(trow
);
201 // Create a cell that will hold the line number (it is generated in the stylesheet using counters).
202 RefPtrWillBeRawPtr
<HTMLTableCellElement
> td
= HTMLTableCellElement::create(tdTag
, *this);
203 td
->setAttribute(classAttr
, "line-number");
204 td
->setIntegralAttribute(valueAttr
, ++m_lineNumber
);
205 trow
->parserAppendChild(td
);
207 // Create a second cell for the line contents
208 td
= HTMLTableCellElement::create(tdTag
, *this);
209 td
->setAttribute(classAttr
, "line-content");
210 trow
->parserAppendChild(td
);
211 m_current
= m_td
= td
;
213 // Open up the needed spans.
214 if (!className
.isEmpty()) {
215 if (className
== "html-attribute-name" || className
== "html-attribute-value")
216 m_current
= addSpanWithClassName("html-tag");
217 m_current
= addSpanWithClassName(className
);
221 void HTMLViewSourceDocument::finishLine()
223 if (!m_current
->hasChildren()) {
224 RefPtrWillBeRawPtr
<HTMLBRElement
> br
= HTMLBRElement::create(*this);
225 m_current
->parserAppendChild(br
);
230 void HTMLViewSourceDocument::addText(const String
& text
, const AtomicString
& className
, SourceAnnotation annotation
)
235 // Add in the content, splitting on newlines.
236 Vector
<String
> lines
;
237 text
.split('\n', true, lines
);
238 unsigned size
= lines
.size();
239 for (unsigned i
= 0; i
< size
; i
++) {
240 String substring
= lines
[i
];
241 if (m_current
== m_tbody
)
243 if (substring
.isEmpty()) {
249 RefPtrWillBeRawPtr
<Element
> oldElement
= m_current
;
250 maybeAddSpanForAnnotation(annotation
);
251 m_current
->parserAppendChild(Text::create(*this, substring
));
252 m_current
= oldElement
;
258 int HTMLViewSourceDocument::addRange(const String
& source
, int start
, int end
, const AtomicString
& className
, bool isLink
, bool isAnchor
, const AtomicString
& link
)
260 ASSERT(start
<= end
);
264 String text
= source
.substring(start
, end
- start
);
265 if (!className
.isEmpty()) {
267 m_current
= addLink(link
, isAnchor
);
269 m_current
= addSpanWithClassName(className
);
271 addText(text
, className
);
272 if (!className
.isEmpty() && m_current
!= m_tbody
)
273 m_current
= toElement(m_current
->parentNode());
277 PassRefPtrWillBeRawPtr
<Element
> HTMLViewSourceDocument::addBase(const AtomicString
& href
)
279 RefPtrWillBeRawPtr
<HTMLBaseElement
> base
= HTMLBaseElement::create(*this);
280 base
->setAttribute(hrefAttr
, href
);
281 m_current
->parserAppendChild(base
);
282 return base
.release();
285 PassRefPtrWillBeRawPtr
<Element
> HTMLViewSourceDocument::addLink(const AtomicString
& url
, bool isAnchor
)
287 if (m_current
== m_tbody
)
290 // Now create a link for the attribute value instead of a span.
291 RefPtrWillBeRawPtr
<HTMLAnchorElement
> anchor
= HTMLAnchorElement::create(*this);
292 const char* classValue
;
294 classValue
= "html-attribute-value html-external-link";
296 classValue
= "html-attribute-value html-resource-link";
297 anchor
->setAttribute(classAttr
, classValue
);
298 anchor
->setAttribute(targetAttr
, "_blank");
299 anchor
->setAttribute(hrefAttr
, url
);
300 m_current
->parserAppendChild(anchor
);
301 return anchor
.release();
304 void HTMLViewSourceDocument::maybeAddSpanForAnnotation(SourceAnnotation annotation
)
306 if (annotation
== AnnotateSourceAsXSS
) {
307 m_current
= addSpanWithClassName("highlight");
308 m_current
->setAttribute(titleAttr
, kXSSDetected
);
313 void HTMLViewSourceDocument::dispose()
318 HTMLDocument::dispose();
322 DEFINE_TRACE(HTMLViewSourceDocument
)
324 visitor
->trace(m_current
);
325 visitor
->trace(m_tbody
);
326 visitor
->trace(m_td
);
327 HTMLDocument::trace(visitor
);