source: webkit/trunk/WebCore/platform/SecurityOrigin.cpp @ 30184

Last change on this file since 30184 was 30184, checked in by beidson@apple.com, 16 years ago

Reviewed by Darin Adler

Fix for <rdar://problem/5737692> - Database API needs to support SuccessCallback

Layout tests will come shortly with a mess of DRT changes

  • platform/SecurityOrigin.cpp: (WebCore::SecurityOrigin::SecurityOrigin): Standardize on "empty string" instead of null string as different paths of constructing a SecurityOrigin were causing different hashes for the "same" SecurityOrigin
  • storage/Database.cpp: (WebCore::Database::changeVersion): Pass in the successCallback (WebCore::Database::transaction): Ditto
  • storage/SQLTransaction.cpp: (WebCore::SQLTransaction::SQLTransaction): (WebCore::SQLTransaction::debugStepName): (WebCore::SQLTransaction::performNextStep): Update ASSERTs for the new valid steps (WebCore::SQLTransaction::performPendingCallback): Ditto (WebCore::SQLTransaction::postflightAndCommit): Schedule the success callback if it exists - otherwise skip straight to cleanupAfterSuccessCallback() (WebCore::SQLTransaction::deliverSuccessCallback): Deliver success callback on the main thread, then schedule cleanupAfterSuccessCallback() (WebCore::SQLTransaction::cleanupAfterSuccessCallback): Cleanup and end the transaction (WebCore::SQLTransaction::handleTransactionError): (WebCore::SQLTransaction::deliverTransactionErrorCallback): (WebCore::SQLTransaction::cleanupAfterTransactionErrorCallback):
  • storage/SQLTransaction.h:
  • Property svn:eol-style set to native
File size: 8.4 KB
Line 
1/*
2 * Copyright (C) 2007 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 *
8 * 1.  Redistributions of source code must retain the above copyright
9 *     notice, this list of conditions and the following disclaimer.
10 * 2.  Redistributions in binary form must reproduce the above copyright
11 *     notice, this list of conditions and the following disclaimer in the
12 *     documentation and/or other materials provided with the distribution.
13 * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 *     its contributors may be used to endorse or promote products derived
15 *     from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include "config.h"
30#include "SecurityOrigin.h"
31
32#include "Document.h"
33#include "Frame.h"
34#include "FrameLoader.h"
35#include "FrameTree.h"
36#include "KURL.h"
37#include "PlatformString.h"
38
39namespace WebCore {
40
41static bool isDefaultPortForProtocol(unsigned short port, String protocol)
42{
43    if (protocol.isEmpty())
44        return false;
45
46    static HashMap<String, unsigned> defaultPorts;
47    if (defaultPorts.isEmpty()) {
48        defaultPorts.set("http", 80);
49        defaultPorts.set("https", 443);
50        defaultPorts.set("ftp", 21);
51        defaultPorts.set("ftps", 990);
52    }
53    return defaultPorts.get(protocol) == port;
54}
55
56SecurityOrigin::SecurityOrigin(const String& protocol, const String& host, unsigned short port)
57    : m_protocol(protocol.isNull() ? "" : protocol.lower())
58    , m_host(host.isNull() ? "" : host.lower())
59    , m_port(port)
60    , m_portSet(port)
61    , m_noAccess(false)
62    , m_domainWasSetInDOM(false)
63{
64    // These protocols do not create security origins; the owner frame provides the origin
65    if (m_protocol == "about" || m_protocol == "javascript")
66        m_protocol = "";
67
68    // data: URLs are not allowed access to anything other than themselves.
69    if (m_protocol == "data")
70        m_noAccess = true;
71
72
73    if (isDefaultPortForProtocol(m_port, m_protocol)) {
74        m_port = 0;
75        m_portSet = false;
76    }   
77}
78
79bool SecurityOrigin::isEmpty() const
80{
81    return m_protocol.isEmpty();
82}
83
84PassRefPtr<SecurityOrigin> SecurityOrigin::create(const String& protocol, const String& host, unsigned short port, SecurityOrigin* ownerFrameOrigin)
85{
86    RefPtr<SecurityOrigin> origin = new SecurityOrigin(protocol, host, port);
87
88    // If we do not obtain a meaningful origin from the URL, then we try to find one
89    // via the frame hierarchy.
90    // We alias the SecurityOrigins to match Firefox, see Bug 15313
91    // http://bugs.webkit.org/show_bug.cgi?id=15313
92    if (origin->isEmpty() && ownerFrameOrigin)
93        return ownerFrameOrigin;
94
95    return origin.release();
96}
97
98PassRefPtr<SecurityOrigin> SecurityOrigin::createForFrame(Frame* frame)
99{
100    if (!frame)
101        return create("", "", 0, 0);
102
103    FrameLoader* loader = frame->loader();
104    KURL url = loader->url();
105
106    Frame* ownerFrame = frame->tree()->parent();
107    if (!ownerFrame)
108        ownerFrame = loader->opener();
109
110    SecurityOrigin* ownerFrameOrigin = 0;
111    if (ownerFrame && ownerFrame->document())
112        ownerFrameOrigin = ownerFrame->document()->securityOrigin();
113
114    return create(url.protocol(), url.host(), url.port(), ownerFrameOrigin);
115}
116
117PassRefPtr<SecurityOrigin> SecurityOrigin::copy()
118{
119    return create(m_protocol.copy(), m_host.copy(), m_port, 0);
120}
121
122
123void SecurityOrigin::setDomainFromDOM(const String& newDomain)
124{
125    m_domainWasSetInDOM = true;
126    m_host = newDomain.lower();
127}
128
129bool SecurityOrigin::canAccess(const SecurityOrigin* other, Reason& reason) const
130
131    if (FrameLoader::shouldTreatSchemeAsLocal(m_protocol))
132        return true;
133
134    if (m_noAccess || other->m_noAccess) {
135        reason = SecurityOrigin::GenericMismatch;
136        return false;
137    }
138
139    // Here are three cases where we should permit access:
140    //
141    // 1) Neither document has set document.domain.  In this case, we insist
142    //    that the scheme, host, and port of the URLs match.
143    //
144    // 2) Both documents have set document.domain.  In this case, we insist
145    //    that the documents have set document.domain to the same value and
146    //    that the scheme of the URLs match.
147    //
148    // 3) As a special case if only one of the documents has set document.domain but
149    //    there is a host and port match we deny access but signal this to the client.
150    //    In this case Window::allowsAccessFrom() will recheck against the lexical global
151    //    object and allow access if that check passes.
152    //
153    // This matches the behavior of Firefox 2 and Internet Explorer 6.
154    //
155    // Internet Explorer 7 and Opera 9 are more strict in that they require
156    // the port numbers to match when both pages have document.domain set.
157    //
158    // FIXME: Evaluate whether we can tighten this policy to require matched
159    //        port numbers.
160    //
161    // Opera 9 allows access when only one page has set document.domain, but
162    // this is a security vulnerability.
163
164    if (m_protocol == other->m_protocol) {
165        if (!m_domainWasSetInDOM && !other->m_domainWasSetInDOM) {
166            if (m_host == other->m_host && m_port == other->m_port)
167                return true;
168        } else if (m_domainWasSetInDOM && other->m_domainWasSetInDOM) {
169            if (m_host == other->m_host)
170                return true;
171        } else {
172            if (m_host == other->m_host && m_port == other->m_port) {
173                reason = DomainSetInDOMMismatch;
174                return false;
175            }
176        }
177    }
178   
179    reason = SecurityOrigin::GenericMismatch;
180    return false;
181}
182
183bool SecurityOrigin::isSecureTransitionTo(const KURL& url) const
184{
185    // New window created by the application
186    if (isEmpty())
187        return true;
188
189    if (FrameLoader::shouldTreatSchemeAsLocal(m_protocol))
190        return true;
191
192    return equalIgnoringCase(m_host, String(url.host())) && equalIgnoringCase(m_protocol, String(url.protocol())) && m_port == url.port();
193}
194
195String SecurityOrigin::toString() const
196{
197    return m_protocol + ":" + m_host + ":" + String::number(m_port);
198}
199
200static const char SeparatorCharacter = '_';
201
202PassRefPtr<SecurityOrigin> SecurityOrigin::createFromIdentifier(const String& stringIdentifier)
203{
204    // Make sure there's a first separator
205    int separator1 = stringIdentifier.find(SeparatorCharacter);
206    if (separator1 == -1)
207        return create("", "", 0, 0);
208       
209    // Make sure there's a second separator
210    int separator2 = stringIdentifier.find(SeparatorCharacter, separator1 + 1);
211    if (separator2 == -1)
212        return create("", "", 0, 0);
213       
214    // Make sure there's not a third separator
215    if (stringIdentifier.reverseFind(SeparatorCharacter) != separator2)
216        return create("", "", 0, 0);
217       
218    // Make sure the port section is a valid port number or doesn't exist
219    bool portOkay;
220    int port = stringIdentifier.right(stringIdentifier.length() - separator2 - 1).toInt(&portOkay);
221    if (!portOkay && separator2 + 1 == static_cast<int>(stringIdentifier.length()))
222        return create("", "", 0, 0);
223   
224    if (port < 0 || port > 65535)
225        return create("", "", 0, 0);
226       
227    // Split out the 3 sections of data
228    String protocol = stringIdentifier.substring(0, separator1);
229    String host = stringIdentifier.substring(separator1 + 1, separator2 - separator1 - 1);
230    return create(protocol, host, port, 0);
231}
232   
233   
234String SecurityOrigin::stringIdentifier() const
235{
236    static String separatorString = String(&SeparatorCharacter, 1);
237    return m_protocol + separatorString + m_host + separatorString + String::number(m_port);
238}
239
240} // namespace WebCore
Note: See TracBrowser for help on using the repository browser.