Changeset 206954 in webkit
- Timestamp:
- Oct 8, 2016 7:49:47 AM (8 years ago)
- Location:
- trunk
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r206949 r206954 1 2016-10-08 Youenn Fablet <youennf@gmail.com> 2 3 [Fetch API] Request constructor should provide exception messages 4 https://bugs.webkit.org/show_bug.cgi?id=162382 5 6 Reviewed by Darin Adler. 7 8 * fetch/fetch-url-serialization-expected.txt: Rebasing test expectation. 9 1 10 2016-10-07 Chris Dumez <cdumez@apple.com> 2 11 -
trunk/LayoutTests/fetch/fetch-url-serialization-expected.txt
r203221 r206954 98 98 FAIL Testing Request url 'C|/foo/bar' with base 'file:///tmp/mock/path' assert_equals: expected "file:///C:/foo/bar" but got "file:///tmp/mock/C|/foo/bar" 99 99 FAIL Testing Request url '/C|\foo\bar' with base 'file:///tmp/mock/path' assert_equals: expected "file:///C:/foo/bar" but got "file:///C|/foo/bar" 100 FAIL Testing Request url '//C|/foo/bar' with base 'file:///tmp/mock/path' Type error100 FAIL Testing Request url '//C|/foo/bar' with base 'file:///tmp/mock/path' URL is not valid or contains user credentials. 101 101 PASS Testing Request url '//server/file' with base 'file:///tmp/mock/path' 102 102 PASS Testing Request url '\\server\file' with base 'file:///tmp/mock/path' -
trunk/Source/WebCore/ChangeLog
r206953 r206954 1 2016-10-08 Youenn Fablet <youenn@apple.com> 2 3 [Fetch API] Request constructor should provide exception messages 4 https://bugs.webkit.org/show_bug.cgi?id=162382 5 6 Reviewed by Darin Adler. 7 8 No change of behavior, except that exceptions now have error messages. 9 10 Added support of exception messages to ExceptionOr. 11 Making use of ExceptionOr for Request constructor parameter checking. 12 13 * Modules/fetch/FetchRequest.cpp: 14 (WebCore::setReferrerPolicy): 15 (WebCore::setMode): 16 (WebCore::setCredentials): 17 (WebCore::setCache): 18 (WebCore::setRedirect): 19 (WebCore::setMethod): 20 (WebCore::setReferrer): 21 (WebCore::buildOptions): 22 (WebCore::FetchRequest::initializeOptions): 23 (WebCore::FetchRequest::initializeWith): 24 * Modules/fetch/FetchRequest.h: 25 * Modules/fetch/FetchRequest.idl: 26 * bindings/js/JSDOMBinding.cpp: 27 (WebCore::setDOMException): 28 * bindings/js/JSDOMBinding.h: 29 (WebCore::toJS): 30 (WebCore::toJSNewlyCreated): 31 * dom/Exception.h: 32 (WebCore::Exception::code): 33 (WebCore::Exception::message): 34 (WebCore::Exception::Exception): 35 * dom/ExceptionOr.h: 36 (WebCore::ExceptionOr<ReturnType>::exceptionMessage): 37 1 38 2016-10-08 Youenn Fablet <youenn@apple.com> 2 39 -
trunk/Source/WebCore/Modules/fetch/FetchRequest.cpp
r206737 r206954 40 40 namespace WebCore { 41 41 42 static boolsetReferrerPolicy(FetchOptions& options, const String& referrerPolicy)42 static Optional<Exception> setReferrerPolicy(FetchOptions& options, const String& referrerPolicy) 43 43 { 44 44 if (referrerPolicy.isEmpty()) … … 55 55 options.referrerPolicy = FetchOptions::ReferrerPolicy::UnsafeUrl; 56 56 else 57 return false;58 return true;59 } 60 61 static boolsetMode(FetchOptions& options, const String& mode)57 return Exception { TypeError, ASCIILiteral("Bad referrer policy value.") }; 58 return Nullopt; 59 } 60 61 static Optional<Exception> setMode(FetchOptions& options, const String& mode) 62 62 { 63 63 if (mode == "navigate") … … 70 70 options.mode = FetchOptions::Mode::Cors; 71 71 else 72 return false;73 return true;74 } 75 76 static boolsetCredentials(FetchOptions& options, const String& credentials)72 return Exception { TypeError, ASCIILiteral("Bad fetch mode value.") }; 73 return Nullopt; 74 } 75 76 static Optional<Exception> setCredentials(FetchOptions& options, const String& credentials) 77 77 { 78 78 if (credentials == "omit") … … 83 83 options.credentials = FetchOptions::Credentials::Include; 84 84 else 85 return false;86 return true;87 } 88 89 static boolsetCache(FetchOptions& options, const String& cache)85 return Exception { TypeError, ASCIILiteral("Bad credentials mode value.") }; 86 return Nullopt; 87 } 88 89 static Optional<Exception> setCache(FetchOptions& options, const String& cache) 90 90 { 91 91 if (cache == "default") … … 100 100 options.cache = FetchOptions::Cache::ForceCache; 101 101 else 102 return false;103 return true;104 } 105 106 static boolsetRedirect(FetchOptions& options, const String& redirect)102 return Exception { TypeError, ASCIILiteral("Bad cache mode value.") }; 103 return Nullopt; 104 } 105 106 static Optional<Exception> setRedirect(FetchOptions& options, const String& redirect) 107 107 { 108 108 if (redirect == "follow") … … 113 113 options.redirect = FetchOptions::Redirect::Manual; 114 114 else 115 return false;116 return true;117 } 118 119 static boolsetMethod(ResourceRequest& request, const String& initMethod)115 return Exception { TypeError, ASCIILiteral("Bad redirect mode value.") }; 116 return Nullopt; 117 } 118 119 static Optional<Exception> setMethod(ResourceRequest& request, const String& initMethod) 120 120 { 121 121 if (!isValidHTTPToken(initMethod)) 122 return false;122 return Exception { TypeError, ASCIILiteral("Method is not a valid HTTP token.") }; 123 123 124 124 String method = initMethod.convertToASCIIUppercase(); 125 125 if (method == "CONNECT" || method == "TRACE" || method == "TRACK") 126 return false;126 return Exception { TypeError, ASCIILiteral("Method is forbidden.") }; 127 127 128 128 request.setHTTPMethod((method == "DELETE" || method == "GET" || method == "HEAD" || method == "OPTIONS" || method == "POST" || method == "PUT") ? method : initMethod); 129 129 130 return true;131 } 132 133 static boolsetReferrer(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const Dictionary& init)130 return Nullopt; 131 } 132 133 static Optional<Exception> setReferrer(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const Dictionary& init) 134 134 { 135 135 String referrer; 136 136 if (!init.get("referrer", referrer)) 137 return true;137 return Nullopt; 138 138 if (referrer.isEmpty()) { 139 139 request.referrer = ASCIILiteral("no-referrer"); 140 return true;140 return Nullopt; 141 141 } 142 142 // FIXME: Tighten the URL parsing algorithm according https://url.spec.whatwg.org/#concept-url-parser. 143 143 URL referrerURL = context.completeURL(referrer); 144 144 if (!referrerURL.isValid()) 145 return false;145 return Exception { TypeError, ASCIILiteral("Referrer is not a valid URL.") }; 146 146 147 147 if (referrerURL.protocolIs("about") && referrerURL.path() == "client") { 148 148 request.referrer = ASCIILiteral("client"); 149 return true;149 return Nullopt; 150 150 } 151 151 152 152 if (!(context.securityOrigin() && context.securityOrigin()->canRequest(referrerURL))) 153 return false;153 return Exception { TypeError, ASCIILiteral("Referrer is not same-origin.") }; 154 154 155 155 request.referrer = referrerURL.string(); 156 return true;157 } 158 159 static boolbuildOptions(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const Dictionary& init)156 return Nullopt; 157 } 158 159 static Optional<Exception> buildOptions(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const Dictionary& init) 160 160 { 161 161 JSC::JSValue window; 162 162 if (init.get("window", window)) { 163 163 if (!window.isNull()) 164 return false; 165 } 166 167 if (!setReferrer(request, context, init)) 168 return false; 164 return Exception { TypeError, ASCIILiteral("Window can only be null.") }; 165 } 166 167 auto exception = setReferrer(request, context, init); 168 if (exception) 169 return exception; 169 170 170 171 String value; 171 if (init.get("referrerPolicy", value) && !setReferrerPolicy(request.options, value)) 172 return false; 173 174 if (init.get("mode", value) && !setMode(request.options, value)) 175 return false; 172 if (init.get("referrerPolicy", value)) { 173 exception = setReferrerPolicy(request.options, value); 174 if (exception) 175 return exception; 176 } 177 178 if (init.get("mode", value)) { 179 exception = setMode(request.options, value); 180 if (exception) 181 return exception; 182 } 176 183 if (request.options.mode == FetchOptions::Mode::Navigate) 177 return false; 178 179 if (init.get("credentials", value) && !setCredentials(request.options, value)) 180 return false; 181 182 if (init.get("cache", value) && !setCache(request.options, value)) 183 return false; 184 185 if (init.get("redirect", value) && !setRedirect(request.options, value)) 186 return false; 184 return Exception { TypeError, ASCIILiteral("Request constructor does not accept navigate fetch mode.") }; 185 186 if (init.get("credentials", value)) { 187 exception = setCredentials(request.options, value); 188 if (exception) 189 return exception; 190 } 191 192 if (init.get("cache", value)) { 193 exception = setCache(request.options, value); 194 if (exception) 195 return exception; 196 } 197 198 if (init.get("redirect", value)) { 199 exception = setRedirect(request.options, value); 200 if (exception) 201 return exception; 202 } 187 203 188 204 init.get("integrity", request.integrity); 189 205 190 if (init.get("method", value) && !setMethod(request.request, value)) 191 return false; 192 193 return true; 206 if (init.get("method", value)) { 207 exception = setMethod(request.request, value); 208 if (exception) 209 return exception; 210 } 211 return Nullopt; 194 212 } 195 213 … … 199 217 } 200 218 201 void FetchRequest::initializeOptions(const Dictionary& init, ExceptionCode& ec)219 ExceptionOr<Ref<FetchHeaders>> FetchRequest::initializeOptions(const Dictionary& init) 202 220 { 203 221 ASSERT(scriptExecutionContext()); 204 if (!buildOptions(m_internalRequest, *scriptExecutionContext(), init)) { 205 ec = TypeError;206 return;207 }222 223 auto exception = buildOptions(m_internalRequest, *scriptExecutionContext(), init); 224 if (exception) 225 return WTFMove(exception.value()); 208 226 209 227 if (m_internalRequest.options.mode == FetchOptions::Mode::NoCors) { 210 228 const String& method = m_internalRequest.request.httpMethod(); 211 if (method != "GET" && method != "POST" && method != "HEAD") { 212 ec = TypeError; 213 return; 214 } 215 if (!m_internalRequest.integrity.isEmpty()) { 216 ec = TypeError; 217 return; 218 } 229 if (method != "GET" && method != "POST" && method != "HEAD") 230 return Exception { TypeError, ASCIILiteral("Method must be GET, POST or HEAD in no-cors mode.") }; 231 if (!m_internalRequest.integrity.isEmpty()) 232 return Exception { TypeError, ASCIILiteral("There cannot be an integrity in no-cors mode.") }; 219 233 m_headers->setGuard(FetchHeaders::Guard::RequestNoCors); 220 234 } 221 } 222 223 FetchHeaders* FetchRequest::initializeWith(const String& url, const Dictionary& init, ExceptionCode& ec) 235 return m_headers.copyRef(); 236 } 237 238 ExceptionOr<Ref<FetchHeaders>> FetchRequest::initializeWith(const String& url, const Dictionary& init) 224 239 { 225 240 ASSERT(scriptExecutionContext()); 226 241 // FIXME: Tighten the URL parsing algorithm according https://url.spec.whatwg.org/#concept-url-parser. 227 242 URL requestURL = scriptExecutionContext()->completeURL(url); 228 if (!requestURL.isValid() || !requestURL.user().isEmpty() || !requestURL.pass().isEmpty()) { 229 ec = TypeError; 230 return nullptr; 231 } 243 if (!requestURL.isValid() || !requestURL.user().isEmpty() || !requestURL.pass().isEmpty()) 244 return Exception { TypeError, ASCIILiteral("URL is not valid or contains user credentials.") }; 232 245 233 246 m_internalRequest.options.mode = Mode::Cors; … … 236 249 m_internalRequest.request.setURL(requestURL); 237 250 238 initializeOptions(init, ec); 239 return m_headers.ptr(); 240 } 241 242 FetchHeaders* FetchRequest::initializeWith(FetchRequest& input, const Dictionary& init, ExceptionCode& ec) 243 { 244 if (input.isDisturbedOrLocked()) { 245 ec = TypeError; 246 return nullptr; 247 } 251 return initializeOptions(init); 252 } 253 254 ExceptionOr<Ref<FetchHeaders>> FetchRequest::initializeWith(FetchRequest& input, const Dictionary& init) 255 { 256 if (input.isDisturbedOrLocked()) 257 return Exception {TypeError, ASCIILiteral("Request input is disturbed or locked.") }; 248 258 249 259 m_internalRequest = input.m_internalRequest; 250 260 251 initializeOptions(init, ec); 252 return m_headers.ptr(); 261 return initializeOptions(init); 253 262 } 254 263 -
trunk/Source/WebCore/Modules/fetch/FetchRequest.h
r206737 r206954 32 32 #if ENABLE(FETCH_API) 33 33 34 #include "ExceptionOr.h" 34 35 #include "FetchBodyOwner.h" 35 36 #include "FetchOptions.h" 36 37 #include "ResourceRequest.h" 38 #include <wtf/Optional.h> 37 39 38 40 namespace WebCore { … … 47 49 static Ref<FetchRequest> create(ScriptExecutionContext& context) { return adoptRef(*new FetchRequest(context, Nullopt, FetchHeaders::create(FetchHeaders::Guard::Request), { })); } 48 50 49 FetchHeaders* initializeWith(FetchRequest&, const Dictionary&, ExceptionCode&);50 FetchHeaders* initializeWith(const String&, const Dictionary&, ExceptionCode&);51 ExceptionOr<Ref<FetchHeaders>> initializeWith(FetchRequest&, const Dictionary&); 52 ExceptionOr<Ref<FetchHeaders>> initializeWith(const String&, const Dictionary&); 51 53 void setBody(JSC::ExecState&, JSC::JSValue, FetchRequest*, ExceptionCode&); 52 54 … … 97 99 FetchRequest(ScriptExecutionContext&, Optional<FetchBody>&&, Ref<FetchHeaders>&&, InternalRequest&&); 98 100 99 void initializeOptions(const Dictionary&, ExceptionCode&);101 ExceptionOr<Ref<FetchHeaders>> initializeOptions(const Dictionary&); 100 102 101 103 // ActiveDOMObject API. -
trunk/Source/WebCore/Modules/fetch/FetchRequest.idl
r206723 r206954 63 63 [NewObject, CallWith=ScriptExecutionContext, MayThrowLegacyException] FetchRequest clone(); 64 64 65 [PrivateIdentifier, MayThrowLegacyException] FetchHeaders initializeWith(FetchRequest input, Dictionary init);66 [PrivateIdentifier, MayThrowLegacyException] FetchHeaders initializeWith(DOMString input, Dictionary init);65 [PrivateIdentifier, NewObject] FetchHeaders initializeWith(FetchRequest input, Dictionary init); 66 [PrivateIdentifier, NewObject] FetchHeaders initializeWith(DOMString input, Dictionary init); 67 67 [PrivateIdentifier, MayThrowLegacyException, CallWith=ScriptState] void setBody(any body, FetchRequest? request); 68 68 }; -
trunk/Source/WebCore/bindings/js/JSDOMBinding.cpp
r206386 r206954 377 377 } 378 378 379 void setDOMException(ExecState* exec, ExceptionCode ec, const String& message) 380 { 381 VM& vm = exec->vm(); 382 auto scope = DECLARE_THROW_SCOPE(vm); 383 384 if (!ec || scope.exception()) 385 return; 386 387 throwException(exec, scope, createDOMException(exec, ec, message)); 388 } 389 379 390 void setDOMException(ExecState* exec, const ExceptionCodeWithMessage& ec) 380 391 { -
trunk/Source/WebCore/bindings/js/JSDOMBinding.h
r206953 r206954 188 188 // Convert a DOM implementation exception code into a JavaScript exception in the execution state. 189 189 WEBCORE_EXPORT void setDOMException(JSC::ExecState*, ExceptionCode); 190 void setDOMException(JSC::ExecState*, ExceptionCode, const String&); 190 191 void setDOMException(JSC::ExecState*, const ExceptionCodeWithMessage&); 191 192 … … 947 948 { 948 949 if (UNLIKELY(value.hasException())) { 949 setDOMException(state, value.exceptionCode() );950 setDOMException(state, value.exceptionCode(), value.exceptionMessage()); 950 951 return JSC::jsUndefined(); 951 952 } … … 957 958 // FIXME: It's really annoying to have two of these functions. Should find a way to combine toJS and toJSNewlyCreated. 958 959 if (UNLIKELY(value.hasException())) { 959 setDOMException(state, value.exceptionCode() );960 setDOMException(state, value.exceptionCode(), value.exceptionMessage()); 960 961 return JSC::jsUndefined(); 961 962 } -
trunk/Source/WebCore/dom/Exception.h
r206245 r206954 27 27 #pragma once 28 28 29 #include <wtf/text/WTFString.h> 30 29 31 namespace WebCore { 30 32 … … 34 36 public: 35 37 explicit Exception(ExceptionCode); 38 explicit Exception(ExceptionCode, const String&); 36 39 37 ExceptionCode code() const; 40 ExceptionCode code() const { return m_code; } 41 const String& message() const { return m_message; } 38 42 39 43 private: 40 44 ExceptionCode m_code; 45 String m_message; 41 46 }; 42 47 … … 46 51 } 47 52 48 inline ExceptionCode Exception::code() const 53 inline Exception::Exception(ExceptionCode code, const String& message) 54 : m_code(code) 55 , m_message(message) 49 56 { 50 return m_code;51 57 } 52 58 -
trunk/Source/WebCore/dom/ExceptionOr.h
r205411 r206954 39 39 bool hasException() const; 40 40 ExceptionCode exceptionCode() const; 41 const String& exceptionMessage() const; 41 42 ReturnType&& takeReturnValue(); 42 43 … … 65 66 } 66 67 68 template<typename ReturnType> inline const String& ExceptionOr<ReturnType>::exceptionMessage() const 69 { 70 return std::experimental::get<Exception>(m_value).message(); 71 } 72 67 73 template<typename ReturnType> inline ReturnType&& ExceptionOr<ReturnType>::takeReturnValue() 68 74 {
Note: See TracChangeset
for help on using the changeset viewer.