Changeset 211248 in webkit
- Timestamp:
- Jan 26, 2017 6:00:17 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 3 added
- 3 deleted
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r211235 r211248 1 2017-01-26 Andy Estes <aestes@apple.com> 2 3 [QuickLook] REGRESSION (WebKit2): Requests are made to invalid x-apple-ql-id: URLs 4 https://bugs.webkit.org/show_bug.cgi?id=167453 5 6 Reviewed by Brent Fulgham. 7 8 * quicklook/invalid-ql-id-url-expected.txt: Added. 9 * quicklook/invalid-ql-id-url.html: Added. 10 * quicklook/nil-response-mime-type-expected.txt: Removed. 11 * quicklook/nil-response-mime-type.html: Removed. 12 * quicklook/resources/invalid-ql-id-url.xls: Added. 13 * quicklook/resources/nil-response-mime-type.xls: Removed. 14 1 15 2017-01-26 Jeremy Jones <jeremyj@apple.com> 2 16 -
trunk/Source/WebCore/ChangeLog
r211247 r211248 1 2017-01-26 Andy Estes <aestes@apple.com> 2 3 [QuickLook] REGRESSION (WebKit2): Requests are made to invalid x-apple-ql-id: URLs 4 https://bugs.webkit.org/show_bug.cgi?id=167453 5 6 Reviewed by Brent Fulgham. 7 8 Requests to x-apple-ql-id: URLs should be filtered by 9 -[QLPreviewConverter safeRequestForRequest:]. This method checks that the URL is one of the 10 ones generated for the current preview, and changes it to "about:" if it isn't. 11 12 WebCore::safeQLURLForDocumentURLAndResourceURL() was responsible for finding the 13 QLPreviewConverter instance to use by looking it up in an NSMutableDictionary using the 14 document URL as a key. In WebKit1, this dictionary was populated by the 15 QuickLookHandleClient when new QuickLookHandles were created, but the WebKit2 16 QuickLookHandleClient never did this. As a result, requests to invalid URLs were not being 17 rewritten. 18 19 An easy way to load a QuickLook document with invalid URLs is to create an HTML file with a 20 Microsoft Office extension (e.g. .xls); QuickLook, iWork, and Office support opening HTML 21 files with Office document extensions. In r207155 we applied a Content Security Policy to 22 QuickLook documents that only allows x-apple-ql-id: resources to load. This blocked 23 cross-origin requests from loading, but same-origin requests to URLs that weren't generated 24 by QLPreviewConverter were still allowed to load. 25 26 This change blocks these URLs by calling -[QLPreviewConverter safeRequestForRequest:] in a 27 way that works for both WebKit1 and WebKit2. 28 29 After implementing QuickLook for WebKit2, we found a bug when loading HTML-as-Office 30 documents (webkit.org/b/135651) that presented as a nil MIME type in the preview 31 NSURLResponse returned by QLPreviewConverter. Unfortunately r172159 papered over the actual 32 bug by failing to load previews with nil MIME types. 33 34 The real issue was that we were asking for the preview response before QuickLook had 35 received enough data to determine a MIME type, so this change also removes the bad fix from 36 r172159 and instead waits until QuickLook has converted the document to ask for its preview 37 response. This restores the ability to load HTML files with Office document extensions. 38 These two fixes are combined in a single patch because I don't know how to create an invalid 39 QuickLook URL for testing without loading an HTML-as-Office document. 40 41 Test: quicklook/invalid-ql-id-url.html 42 43 * loader/ResourceLoader.cpp: 44 (WebCore::ResourceLoader::willSendRequestInternal): Called 45 QuickLookHandle::willSendRequest() if m_documentLoader has a QuickLookHandle. 46 * loader/cache/CachedResource.cpp: 47 (WebCore::CachedResource::load): Removed the call to 48 WebCore::safeQLURLForDocumentURLAndResourceURL(). 49 * loader/ios/QuickLook.h: Removed safeQLURLForDocumentURLAndResourceURL() and declared 50 QuickLookHandle::willSendRequest(). 51 * loader/ios/QuickLook.mm: Removed _previewResponse and _hasFailed ivars from 52 WebPreviewConverter. 53 (-[WebPreviewConverter initWithResourceLoader:resourceResponse:quickLookHandle:]): Stopped 54 setting _previewResponse. 55 (-[WebPreviewConverter _sendDidReceiveResponseIfNecessary]): Only emptied _bufferedDataArray 56 if we haven't already called -_sendDidReceiveResponseIfNecessary; removed the check for a 57 nil _previewResponse MIME type; accessed -[QLPreviewConverter previewResponse] now that the 58 document has been converted and asserted its MIME type is non-nil. 59 (-[WebPreviewConverter connection:didReceiveData:lengthReceived:]): Removed _hasFailed check. 60 (-[WebPreviewConverter connectionDidFinishLoading:]): Ditto. 61 (isQuickLookPasswordError): Moved the check for password failure errors to here from 62 -connection:didFailWithError: for better readability. 63 (-[WebPreviewConverter connection:didFailWithError:]): Removed _hasFailed check and used 64 more early returns. 65 (WebCore::QuickLookHandle::willSendRequest): Filtered the request through 66 -[QLPreviewConverter safeRequestWithRequest:] if the request URL's scheme is x-apple-ql-id:. 67 (WebCore::safeQLURLForDocumentURLAndResourceURL): Deleted. 68 1 69 2017-01-26 Keith Miller <keith_miller@apple.com> 2 70 -
trunk/Source/WebCore/loader/ResourceLoader.cpp
r210859 r211248 56 56 #endif 57 57 58 #if USE(QUICK_LOOK) 59 #include "QuickLook.h" 60 #endif 61 58 62 namespace WebCore { 59 63 … … 371 375 else 372 376 InspectorInstrumentation::willSendRequest(m_frame.get(), m_identifier, m_frame->loader().documentLoader(), request, redirectResponse); 377 378 #if USE(QUICK_LOOK) 379 if (auto quickLookHandle = m_documentLoader->quickLookHandle()) 380 quickLookHandle->willSendRequest(request); 381 #endif 373 382 374 383 bool isRedirect = !redirectResponse.isNull(); -
trunk/Source/WebCore/loader/cache/CachedResource.cpp
r210697 r211248 215 215 m_loading = true; 216 216 217 #if USE(QUICK_LOOK)218 if (!m_resourceRequest.isNull() && m_resourceRequest.url().protocolIs(QLPreviewProtocol())) {219 // When QuickLook is invoked to convert a document, it returns a unique URL in the220 // NSURLReponse for the main document. To make safeQLURLForDocumentURLAndResourceURL()221 // work, we need to use the QL URL not the original URL.222 const URL& documentURL = frameLoader.documentLoader()->response().url();223 m_resourceRequest.setURL(safeQLURLForDocumentURLAndResourceURL(documentURL, url()));224 }225 #endif226 227 217 if (isCacheValidator()) { 228 218 CachedResource* resourceToRevalidate = m_resourceToRevalidate; -
trunk/Source/WebCore/loader/ios/QuickLook.h
r211236 r211248 47 47 class QuickLookHandleClient; 48 48 class ResourceLoader; 49 class ResourceRequest; 49 50 class ResourceResponse; 50 51 class SharedBuffer; … … 60 61 WEBCORE_EXPORT RetainPtr<NSURLRequest> registerQLPreviewConverterIfNeeded(NSURL *, NSString *mimeType, NSData *); 61 62 62 const URL safeQLURLForDocumentURLAndResourceURL(const URL& documentURL, const String& resourceURL);63 64 63 WEBCORE_EXPORT const char* QLPreviewProtocol(); 65 64 … … 73 72 ~QuickLookHandle(); 74 73 74 void willSendRequest(ResourceRequest&); 75 75 bool didReceiveData(const char* data, unsigned length); 76 76 bool didReceiveBuffer(const SharedBuffer&); -
trunk/Source/WebCore/loader/ios/QuickLook.mm
r211236 r211248 35 35 #import "ResourceError.h" 36 36 #import "ResourceLoader.h" 37 #import "ResourceRequest.h" 37 38 #import "SharedBuffer.h" 38 39 #import <wtf/NeverDestroyed.h> … … 124 125 125 126 return nil; 126 }127 128 const URL WebCore::safeQLURLForDocumentURLAndResourceURL(const URL& documentURL, const String& resourceURL)129 {130 id converter = nil;131 NSURL *nsDocumentURL = documentURL;132 {133 LockHolder lock(qlPreviewConverterDictionaryMutex());134 converter = [QLPreviewConverterDictionary() objectForKey:nsDocumentURL];135 }136 137 if (!converter)138 return URL(ParsedURLString, resourceURL);139 140 RetainPtr<NSURLRequest> request = adoptNS([[NSURLRequest alloc] initWithURL:[NSURL URLWithString:resourceURL]]);141 NSURLRequest *safeRequest = [converter safeRequestForRequest:request.get()];142 return [safeRequest URL];143 127 } 144 128 … … 182 166 RetainPtr<NSURLResponse> _originalResponse; 183 167 RetainPtr<QLPreviewConverter> _platformConverter; 184 RetainPtr<NSURLResponse> _previewResponse;185 168 RetainPtr<NSMutableArray> _bufferedDataArray; 186 169 BOOL _hasSentDidReceiveResponse; 187 BOOL _hasFailed;188 170 } 189 171 … … 211 193 _originalResponse = resourceResponse.nsURLResponse(); 212 194 _platformConverter = adoptNS([allocQLPreviewConverterInstance() initWithConnection:nil delegate:self response:_originalResponse.get() options:nil]); 213 _previewResponse = [_platformConverter previewResponse];214 195 _bufferedDataArray = adoptNS([[NSMutableArray alloc] init]); 215 196 … … 253 234 - (void)_sendDidReceiveResponseIfNecessary 254 235 { 236 if (_hasSentDidReceiveResponse) 237 return; 238 255 239 [_bufferedDataArray removeAllObjects]; 256 240 257 if (_hasSentDidReceiveResponse || _hasFailed) 258 return; 259 260 // QuickLook might fail to convert a document without calling connection:didFailWithError: (see <rdar://problem/17927972>). 261 // A nil MIME type is an indication of such a failure, so stop loading the resource and ignore subsequent delegate messages. 262 if (![_previewResponse MIMEType]) { 263 _hasFailed = YES; 264 _resourceLoader->didFail(_resourceLoader->cannotShowURLError()); 265 return; 266 } 267 268 ResourceResponse response { _previewResponse.get() }; 241 ResourceResponse response { [_platformConverter previewResponse] }; 269 242 response.setIsQuickLook(true); 243 ASSERT(response.mimeType().length()); 270 244 271 245 _hasSentDidReceiveResponse = YES; … … 277 251 ASSERT_UNUSED(connection, !connection); 278 252 [self _sendDidReceiveResponseIfNecessary]; 279 if (_hasFailed)280 return;281 253 282 254 // QuickLook code sends us a nil data at times. The check below is the same as the one in … … 289 261 { 290 262 ASSERT_UNUSED(connection, !connection); 291 if (_hasFailed)292 return;293 294 263 ASSERT(_hasSentDidReceiveResponse); 295 264 _resourceLoader->didFinishLoading(0); 296 265 } 297 266 267 static inline bool isQuickLookPasswordError(NSError *error) 268 { 269 return error.code == kQLReturnPasswordProtected && [error.domain isEqualToString:@"QuickLookErrorDomain"]; 270 } 271 298 272 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 299 273 { 300 274 ASSERT_UNUSED(connection, !connection); 301 275 302 if (error.code == kQLReturnPasswordProtected && [error.domain isEqualToString:@"QuickLookErrorDomain"]) { 303 if (!_client->supportsPasswordEntry()) { 304 _resourceLoader->didFail(_resourceLoader->cannotShowURLError()); 305 return; 306 } 307 308 _client->didRequestPassword([retainedSelf = retainPtr(self)] (const String& password) { 309 NSDictionary *passwordOption = @{ (NSString *)kQLPreviewOptionPasswordKey : password }; 310 auto converterWithPassword = adoptNS([allocQLPreviewConverterInstance() initWithConnection:nil delegate:retainedSelf.get() response:retainedSelf->_originalResponse.get() options:passwordOption]); 311 [converterWithPassword appendDataArray:retainedSelf->_bufferedDataArray.get()]; 312 [converterWithPassword finishedAppendingData]; 313 retainedSelf->_previewResponse = [converterWithPassword previewResponse]; 314 retainedSelf->_platformConverter = WTFMove(converterWithPassword); 315 }); 276 if (!isQuickLookPasswordError(error)) { 277 [self _sendDidReceiveResponseIfNecessary]; 278 _resourceLoader->didFail(error); 316 279 return; 317 280 } 318 281 319 [self _sendDidReceiveResponseIfNecessary]; 320 if (!_hasFailed) 321 _resourceLoader->didFail(error); 282 if (!_client->supportsPasswordEntry()) { 283 _resourceLoader->didFail(_resourceLoader->cannotShowURLError()); 284 return; 285 } 286 287 _client->didRequestPassword([retainedSelf = retainPtr(self)] (const String& password) { 288 NSDictionary *passwordOption = @{ (NSString *)kQLPreviewOptionPasswordKey : password }; 289 auto converterWithPassword = adoptNS([allocQLPreviewConverterInstance() initWithConnection:nil delegate:retainedSelf.get() response:retainedSelf->_originalResponse.get() options:passwordOption]); 290 [converterWithPassword appendDataArray:retainedSelf->_bufferedDataArray.get()]; 291 [converterWithPassword finishedAppendingData]; 292 retainedSelf->_platformConverter = WTFMove(converterWithPassword); 293 }); 322 294 } 323 295 … … 390 362 } 391 363 364 void QuickLookHandle::willSendRequest(ResourceRequest& request) 365 { 366 if (request.url().protocolIs(QLPreviewProtocol())) 367 request = [[m_converter platformConverter] safeRequestForRequest:request.nsURLRequest(DoNotUpdateHTTPBody)]; 368 } 369 392 370 bool QuickLookHandle::didReceiveData(const char* data, unsigned length) 393 371 {
Note: See TracChangeset
for help on using the changeset viewer.