1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * Copyright (C) 2009 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "config.h" 33 34 #if ENABLE(NOTIFICATIONS) 35 36 #include "Notification.h" 37 #include "NotificationCenter.h" 38 #include "NotificationContents.h" 39 40 #include "Document.h" 41 #include "EventNames.h" 42 #include "ResourceRequest.h" 43 #include "ResourceResponse.h" 44 #include "ThreadableLoader.h" 45 #include "WorkerContext.h" 46 47 namespace WebCore { 48 49 Notification::Notification(const KURL& url, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 50 : ActiveDOMObject(context, this) 51 , m_isHTML(true) 52 , m_state(Idle) 53 , m_notificationCenter(provider) 54 { 55 ASSERT(m_notificationCenter->presenter()); 56 if (m_notificationCenter->presenter()->checkPermission(context) != NotificationPresenter::PermissionAllowed) { 57 ec = SECURITY_ERR; 58 return; 59 } 60 61 if (url.isEmpty() || !url.isValid()) { 62 ec = SYNTAX_ERR; 63 return; 64 } 65 66 m_notificationURL = url; 67 } 68 69 Notification::Notification(const NotificationContents& contents, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 70 : ActiveDOMObject(context, this) 71 , m_isHTML(false) 72 , m_contents(contents) 73 , m_state(Idle) 74 , m_notificationCenter(provider) 75 { 76 ASSERT(m_notificationCenter->presenter()); 77 if (m_notificationCenter->presenter()->checkPermission(context) != NotificationPresenter::PermissionAllowed) { 78 ec = SECURITY_ERR; 79 return; 80 } 81 82 if (!contents.icon().isEmpty() && !contents.icon().isValid()) { 83 ec = SYNTAX_ERR; 84 return; 85 } 86 } 87 88 Notification::~Notification() 89 { 90 if (m_state == Loading) { 91 ASSERT_NOT_REACHED(); 92 cancel(); 93 } 94 } 95 96 PassRefPtr<Notification> Notification::create(const KURL& url, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 97 { 98 return adoptRef(new Notification(url, context, ec, provider)); 99 } 100 101 PassRefPtr<Notification> Notification::create(const NotificationContents& contents, ScriptExecutionContext* context, ExceptionCode& ec, PassRefPtr<NotificationCenter> provider) 102 { 103 return adoptRef(new Notification(contents, context, ec, provider)); 104 } 105 106 void Notification::show() 107 { 108 #if PLATFORM(QT) 109 if (iconURL().isEmpty()) { 110 // Set the state before actually showing, because 111 // handling of ondisplay may rely on that. 112 if (m_state == Idle) { 113 m_state = Showing; 114 if (m_notificationCenter->presenter()) 115 m_notificationCenter->presenter()->show(this); 116 } 117 } else 118 startLoading(); 119 #else 120 // prevent double-showing 121 if (m_state == Idle && m_notificationCenter->presenter() && m_notificationCenter->presenter()->show(this)) 122 m_state = Showing; 123 #endif 124 } 125 126 void Notification::cancel() 127 { 128 switch (m_state) { 129 case Idle: 130 break; 131 case Loading: 132 m_state = Cancelled; 133 stopLoading(); 134 break; 135 case Showing: 136 if (m_notificationCenter->presenter()) 137 m_notificationCenter->presenter()->cancel(this); 138 break; 139 case Cancelled: 140 break; 141 } 142 } 143 144 EventTargetData* Notification::eventTargetData() 145 { 146 return &m_eventTargetData; 147 } 148 149 EventTargetData* Notification::ensureEventTargetData() 150 { 151 return &m_eventTargetData; 152 } 153 154 void Notification::contextDestroyed() 155 { 156 ActiveDOMObject::contextDestroyed(); 157 if (m_notificationCenter->presenter()) 158 m_notificationCenter->presenter()->notificationObjectDestroyed(this); 159 } 160 161 void Notification::startLoading() 162 { 163 if (m_state != Idle) 164 return; 165 setPendingActivity(this); 166 m_state = Loading; 167 ThreadableLoaderOptions options; 168 options.sendLoadCallbacks = false; 169 options.sniffContent = false; 170 options.forcePreflight = false; 171 options.allowCredentials = AllowStoredCredentials; 172 options.crossOriginRequestPolicy = AllowCrossOriginRequests; 173 m_loader = ThreadableLoader::create(scriptExecutionContext(), this, ResourceRequest(iconURL()), options); 174 } 175 176 void Notification::stopLoading() 177 { 178 m_iconData = 0; 179 RefPtr<ThreadableLoader> protect(m_loader); 180 m_loader->cancel(); 181 } 182 183 void Notification::didReceiveResponse(const ResourceResponse& response) 184 { 185 int status = response.httpStatusCode(); 186 if (status && (status < 200 || status > 299)) { 187 stopLoading(); 188 return; 189 } 190 m_iconData = SharedBuffer::create(); 191 } 192 193 void Notification::didReceiveData(const char* data, int dataLength) 194 { 195 m_iconData->append(data, dataLength); 196 } 197 198 void Notification::didFinishLoading(unsigned long, double) 199 { 200 finishLoading(); 201 } 202 203 void Notification::didFail(const ResourceError&) 204 { 205 finishLoading(); 206 } 207 208 void Notification::didFailRedirectCheck() 209 { 210 finishLoading(); 211 } 212 213 void Notification::didReceiveAuthenticationCancellation(const ResourceResponse&) 214 { 215 finishLoading(); 216 } 217 218 void Notification::finishLoading() 219 { 220 if (m_state == Loading) { 221 if (m_notificationCenter->presenter() && m_notificationCenter->presenter()->show(this)) 222 m_state = Showing; 223 } 224 unsetPendingActivity(this); 225 } 226 227 } // namespace WebCore 228 229 #endif // ENABLE(NOTIFICATIONS) 230