• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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.
23  */
24 
25 #include "config.h"
26 #include "core/html/HTMLViewSourceDocument.h"
27 
28 #include "core/HTMLNames.h"
29 #include "core/dom/StyleEngine.h"
30 #include "core/dom/Text.h"
31 #include "core/html/HTMLAnchorElement.h"
32 #include "core/html/HTMLBRElement.h"
33 #include "core/html/HTMLBaseElement.h"
34 #include "core/html/HTMLBodyElement.h"
35 #include "core/html/HTMLDivElement.h"
36 #include "core/html/HTMLHeadElement.h"
37 #include "core/html/HTMLHtmlElement.h"
38 #include "core/html/HTMLSpanElement.h"
39 #include "core/html/HTMLTableCellElement.h"
40 #include "core/html/HTMLTableElement.h"
41 #include "core/html/HTMLTableRowElement.h"
42 #include "core/html/HTMLTableSectionElement.h"
43 #include "core/html/parser/HTMLToken.h"
44 #include "core/html/parser/HTMLViewSourceParser.h"
45 
46 namespace WebCore {
47 
48 using namespace HTMLNames;
49 
50 namespace {
51 
52 const char kXSSDetected[] = "Token contains a reflected XSS vector";
53 
54 } // namespace
55 
HTMLViewSourceDocument(const DocumentInit & initializer,const String & mimeType)56 HTMLViewSourceDocument::HTMLViewSourceDocument(const DocumentInit& initializer, const String& mimeType)
57     : HTMLDocument(initializer)
58     , m_type(mimeType)
59 {
60     setIsViewSource(true);
61 
62     // FIXME: Why do view-source pages need to load in quirks mode?
63     setCompatibilityMode(QuirksMode);
64     lockCompatibilityMode();
65 }
66 
createParser()67 PassRefPtrWillBeRawPtr<DocumentParser> HTMLViewSourceDocument::createParser()
68 {
69     return HTMLViewSourceParser::create(*this, m_type);
70 }
71 
createContainingTable()72 void HTMLViewSourceDocument::createContainingTable()
73 {
74     RefPtrWillBeRawPtr<HTMLHtmlElement> html = HTMLHtmlElement::create(*this);
75     parserAppendChild(html);
76     RefPtrWillBeRawPtr<HTMLHeadElement> head = HTMLHeadElement::create(*this);
77     html->parserAppendChild(head);
78     RefPtrWillBeRawPtr<HTMLBodyElement> body = HTMLBodyElement::create(*this);
79     html->parserAppendChild(body);
80 
81     // Create a line gutter div that can be used to make sure the gutter extends down the height of the whole
82     // document.
83     RefPtrWillBeRawPtr<HTMLDivElement> div = HTMLDivElement::create(*this);
84     div->setAttribute(classAttr, "webkit-line-gutter-backdrop");
85     body->parserAppendChild(div);
86 
87     RefPtrWillBeRawPtr<HTMLTableElement> table = HTMLTableElement::create(*this);
88     body->parserAppendChild(table);
89     m_tbody = HTMLTableSectionElement::create(tbodyTag, *this);
90     table->parserAppendChild(m_tbody);
91     m_current = m_tbody;
92     m_lineNumber = 0;
93 }
94 
addSource(const String & source,HTMLToken & token,SourceAnnotation annotation)95 void HTMLViewSourceDocument::addSource(const String& source, HTMLToken& token, SourceAnnotation annotation)
96 {
97     if (!m_current)
98         createContainingTable();
99 
100     switch (token.type()) {
101     case HTMLToken::Uninitialized:
102         ASSERT_NOT_REACHED();
103         break;
104     case HTMLToken::DOCTYPE:
105         processDoctypeToken(source, token);
106         break;
107     case HTMLToken::EndOfFile:
108         processEndOfFileToken(source, token);
109         break;
110     case HTMLToken::StartTag:
111     case HTMLToken::EndTag:
112         processTagToken(source, token, annotation);
113         break;
114     case HTMLToken::Comment:
115         processCommentToken(source, token);
116         break;
117     case HTMLToken::Character:
118         processCharacterToken(source, token, annotation);
119         break;
120     }
121 }
122 
processDoctypeToken(const String & source,HTMLToken &)123 void HTMLViewSourceDocument::processDoctypeToken(const String& source, HTMLToken&)
124 {
125     m_current = addSpanWithClassName("webkit-html-doctype");
126     addText(source, "webkit-html-doctype");
127     m_current = m_td;
128 }
129 
processEndOfFileToken(const String & source,HTMLToken &)130 void HTMLViewSourceDocument::processEndOfFileToken(const String& source, HTMLToken&)
131 {
132     m_current = addSpanWithClassName("webkit-html-end-of-file");
133     addText(source, "webkit-html-end-of-file");
134     m_current = m_td;
135 }
136 
processTagToken(const String & source,HTMLToken & token,SourceAnnotation annotation)137 void HTMLViewSourceDocument::processTagToken(const String& source, HTMLToken& token, SourceAnnotation annotation)
138 {
139     maybeAddSpanForAnnotation(annotation);
140     m_current = addSpanWithClassName("webkit-html-tag");
141 
142     AtomicString tagName(token.name());
143 
144     unsigned index = 0;
145     HTMLToken::AttributeList::const_iterator iter = token.attributes().begin();
146     while (index < source.length()) {
147         if (iter == token.attributes().end()) {
148             // We want to show the remaining characters in the token.
149             index = addRange(source, index, source.length(), emptyAtom);
150             ASSERT(index == source.length());
151             break;
152         }
153 
154         AtomicString name(iter->name);
155         AtomicString value(StringImpl::create8BitIfPossible(iter->value));
156 
157         index = addRange(source, index, iter->nameRange.start - token.startIndex(), emptyAtom);
158         index = addRange(source, index, iter->nameRange.end - token.startIndex(), "webkit-html-attribute-name");
159 
160         if (tagName == baseTag && name == hrefAttr)
161             addBase(value);
162 
163         index = addRange(source, index, iter->valueRange.start - token.startIndex(), emptyAtom);
164 
165         bool isLink = name == srcAttr || name == hrefAttr;
166         index = addRange(source, index, iter->valueRange.end - token.startIndex(), "webkit-html-attribute-value", isLink, tagName == aTag, value);
167 
168         ++iter;
169     }
170     m_current = m_td;
171 }
172 
processCommentToken(const String & source,HTMLToken &)173 void HTMLViewSourceDocument::processCommentToken(const String& source, HTMLToken&)
174 {
175     m_current = addSpanWithClassName("webkit-html-comment");
176     addText(source, "webkit-html-comment");
177     m_current = m_td;
178 }
179 
processCharacterToken(const String & source,HTMLToken &,SourceAnnotation annotation)180 void HTMLViewSourceDocument::processCharacterToken(const String& source, HTMLToken&, SourceAnnotation annotation)
181 {
182     addText(source, "", annotation);
183 }
184 
addSpanWithClassName(const AtomicString & className)185 PassRefPtrWillBeRawPtr<Element> HTMLViewSourceDocument::addSpanWithClassName(const AtomicString& className)
186 {
187     if (m_current == m_tbody) {
188         addLine(className);
189         return m_current;
190     }
191 
192     RefPtrWillBeRawPtr<HTMLSpanElement> span = HTMLSpanElement::create(*this);
193     span->setAttribute(classAttr, className);
194     m_current->parserAppendChild(span);
195     return span.release();
196 }
197 
addLine(const AtomicString & className)198 void HTMLViewSourceDocument::addLine(const AtomicString& className)
199 {
200     // Create a table row.
201     RefPtrWillBeRawPtr<HTMLTableRowElement> trow = HTMLTableRowElement::create(*this);
202     m_tbody->parserAppendChild(trow);
203 
204     // Create a cell that will hold the line number (it is generated in the stylesheet using counters).
205     RefPtrWillBeRawPtr<HTMLTableCellElement> td = HTMLTableCellElement::create(tdTag, *this);
206     td->setAttribute(classAttr, "webkit-line-number");
207     td->setIntegralAttribute(valueAttr, ++m_lineNumber);
208     trow->parserAppendChild(td);
209 
210     // Create a second cell for the line contents
211     td = HTMLTableCellElement::create(tdTag, *this);
212     td->setAttribute(classAttr, "webkit-line-content");
213     trow->parserAppendChild(td);
214     m_current = m_td = td;
215 
216     // Open up the needed spans.
217     if (!className.isEmpty()) {
218         if (className == "webkit-html-attribute-name" || className == "webkit-html-attribute-value")
219             m_current = addSpanWithClassName("webkit-html-tag");
220         m_current = addSpanWithClassName(className);
221     }
222 }
223 
finishLine()224 void HTMLViewSourceDocument::finishLine()
225 {
226     if (!m_current->hasChildren()) {
227         RefPtrWillBeRawPtr<HTMLBRElement> br = HTMLBRElement::create(*this);
228         m_current->parserAppendChild(br);
229     }
230     m_current = m_tbody;
231 }
232 
addText(const String & text,const AtomicString & className,SourceAnnotation annotation)233 void HTMLViewSourceDocument::addText(const String& text, const AtomicString& className, SourceAnnotation annotation)
234 {
235     if (text.isEmpty())
236         return;
237 
238     // Add in the content, splitting on newlines.
239     Vector<String> lines;
240     text.split('\n', true, lines);
241     unsigned size = lines.size();
242     for (unsigned i = 0; i < size; i++) {
243         String substring = lines[i];
244         if (m_current == m_tbody)
245             addLine(className);
246         if (substring.isEmpty()) {
247             if (i == size - 1)
248                 break;
249             finishLine();
250             continue;
251         }
252         RefPtrWillBeRawPtr<Element> oldElement = m_current;
253         maybeAddSpanForAnnotation(annotation);
254         m_current->parserAppendChild(Text::create(*this, substring));
255         m_current = oldElement;
256         if (i < size - 1)
257             finishLine();
258     }
259 }
260 
addRange(const String & source,int start,int end,const AtomicString & className,bool isLink,bool isAnchor,const AtomicString & link)261 int HTMLViewSourceDocument::addRange(const String& source, int start, int end, const AtomicString& className, bool isLink, bool isAnchor, const AtomicString& link)
262 {
263     ASSERT(start <= end);
264     if (start == end)
265         return start;
266 
267     String text = source.substring(start, end - start);
268     if (!className.isEmpty()) {
269         if (isLink)
270             m_current = addLink(link, isAnchor);
271         else
272             m_current = addSpanWithClassName(className);
273     }
274     addText(text, className);
275     if (!className.isEmpty() && m_current != m_tbody)
276         m_current = toElement(m_current->parentNode());
277     return end;
278 }
279 
addBase(const AtomicString & href)280 PassRefPtrWillBeRawPtr<Element> HTMLViewSourceDocument::addBase(const AtomicString& href)
281 {
282     RefPtrWillBeRawPtr<HTMLBaseElement> base = HTMLBaseElement::create(*this);
283     base->setAttribute(hrefAttr, href);
284     m_current->parserAppendChild(base);
285     return base.release();
286 }
287 
addLink(const AtomicString & url,bool isAnchor)288 PassRefPtrWillBeRawPtr<Element> HTMLViewSourceDocument::addLink(const AtomicString& url, bool isAnchor)
289 {
290     if (m_current == m_tbody)
291         addLine("webkit-html-tag");
292 
293     // Now create a link for the attribute value instead of a span.
294     RefPtrWillBeRawPtr<HTMLAnchorElement> anchor = HTMLAnchorElement::create(*this);
295     const char* classValue;
296     if (isAnchor)
297         classValue = "webkit-html-attribute-value webkit-html-external-link";
298     else
299         classValue = "webkit-html-attribute-value webkit-html-resource-link";
300     anchor->setAttribute(classAttr, classValue);
301     anchor->setAttribute(targetAttr, "_blank");
302     anchor->setAttribute(hrefAttr, url);
303     m_current->parserAppendChild(anchor);
304     return anchor.release();
305 }
306 
maybeAddSpanForAnnotation(SourceAnnotation annotation)307 void HTMLViewSourceDocument::maybeAddSpanForAnnotation(SourceAnnotation annotation)
308 {
309     if (annotation == AnnotateSourceAsXSS) {
310         m_current = addSpanWithClassName("webkit-highlight");
311         m_current->setAttribute(titleAttr, kXSSDetected);
312     }
313 }
314 
trace(Visitor * visitor)315 void HTMLViewSourceDocument::trace(Visitor* visitor)
316 {
317     visitor->trace(m_current);
318     visitor->trace(m_tbody);
319     visitor->trace(m_td);
320     HTMLDocument::trace(visitor);
321 }
322 
323 }
324