1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import "ios/web/web_state/ui/crw_static_file_web_view.h"
7 #include "base/logging.h"
8 #include "ios/web/net/request_group_util.h"
9 #include "ios/web/net/request_tracker_impl.h"
10 #include "ios/web/public/browser_state.h"
11 #import "ios/web/ui_web_view_util.h"
12 #include "net/http/http_response_headers.h"
15 NSString* const kStaticFileUserAgent = @"UIWebViewForStaticFileContent";
18 @interface CRWStaticFileWebView () {
19 // Saves the user agent in order to set it on future requests.
20 base::scoped_nsobject<NSString> userAgent_;
21 // Saves the identification assigned to this web view for request
22 // tracking. This identifiation is required for terminating request
24 scoped_refptr<web::RequestTrackerImpl> requestTracker_;
27 // Whether the User-Agent is the allowed user agent.
28 + (BOOL)isStaticFileUserAgent:(NSString*)userAgent;
31 @implementation CRWStaticFileWebView
33 - (instancetype)initWithFrame:(CGRect)frame
34 browserState:(web::BrowserState*)browserState {
35 // Register the user agent before instantiating the UIWebView.
36 NSString* requestGroupID = nil;
37 NSString* userAgent = kStaticFileUserAgent;
39 requestGroupID = web::GenerateNewRequestGroupID();
40 userAgent = web::AddRequestGroupIDToUserAgent(userAgent, requestGroupID);
42 web::RegisterUserAgentForUIWebView(userAgent);
43 self = [super initWithFrame:frame];
45 DCHECK(!browserState || [requestGroupID length]);
47 userAgent_.reset([userAgent copy]);
48 // If |browserState| is not nullptr, associate this UIWebView with the
49 // given |requestGroupID| which cannot be nil or zero-length.
50 // RequestTracker keeps track of requests to this requestGroupID until
51 // this UIWebView is deallocated. UIWebViews not associated with a
52 // requestGroupID will issue requests in the global request context.
53 base::scoped_nsobject<NSString> requestGroupIDCopy([requestGroupID copy]);
54 requestTracker_ = web::RequestTrackerImpl::CreateTrackerForRequestGroupID(
57 browserState->GetRequestContext(),
65 if (requestTracker_.get())
66 requestTracker_->Close();
70 + (BOOL)isStaticFileRequest:(NSURLRequest*)request {
71 NSString* userAgent = [request allHTTPHeaderFields][@"User-Agent"];
73 return [CRWStaticFileWebView isStaticFileUserAgent:userAgent];
76 // If a request originated from another file:/// page, the User-Agent
77 // will not be there. To be safe, check that the request is for image
79 // TODO(pkl): This current test to allow nil User-Agent and images to
80 // be loaded. A more air-tight implementation should inline images as
81 // "data" instead. See crbug.com/228603
82 NSString* suffix = [[request URL] pathExtension];
83 return [@[ @"png", @"jpg", @"jpeg" ] containsObject:[suffix lowercaseString]];
86 + (BOOL)isStaticFileUserAgent:(NSString*)userAgent {
87 return [userAgent hasPrefix:kStaticFileUserAgent];
91 #pragma mark UIWebView
93 // On iOS 6.0, UIWebView does not set the user agent for static file requests.
94 // The solution consists of overriding |loadRequest:| and setting the user agent
95 // before loading the request.
96 - (void)loadRequest:(NSURLRequest*)request {
97 base::scoped_nsobject<NSMutableURLRequest> mutableRequest(
98 (NSMutableURLRequest*)[request mutableCopy]);
99 [mutableRequest setValue:userAgent_ forHTTPHeaderField:@"User-Agent"];
100 [super loadRequest:mutableRequest];
104 #pragma mark CRWRequestTrackerDelegate
106 - (BOOL)isForStaticFileRequests {
110 - (void)handleResponseHeaders:(net::HttpResponseHeaders*)headers
111 requestUrl:(const GURL&)requestUrl {
112 std::string mimeType;
113 DCHECK(headers->GetMimeType(&mimeType) && mimeType == "text/html");
114 DCHECK(!headers->HasHeader("X-Auto-Login"));
115 DCHECK(!headers->HasHeader("content-disposition"));
118 // The following delegate functions are not expected to be called since
119 // the page is intended to be a static HTML page.
121 - (void)updatedSSLStatus:(const web::SSLStatus&)sslStatus
122 forPageUrl:(const GURL&)url
123 userInfo:(id)userInfo {
127 - (void)presentSSLError:(const net::SSLInfo&)info
128 forSSLStatus:(const web::SSLStatus&)status
129 onUrl:(const GURL&)url
130 recoverable:(BOOL)recoverable
131 callback:(SSLErrorCallback)shouldContinue {
135 - (void)updatedProgress:(float)progress {
139 - (void)certificateUsed:(net::X509Certificate*)certificate
140 forHost:(const std::string&)host
141 status:(net::CertStatus)status {
145 - (void)clearCertificates {