Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: components/webp_transcode/webp_network_client.mm

Issue 1022813002: [iOS] Upstream WebP network client (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 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.
4
5 #import "components/webp_transcode/webp_network_client.h"
6
7 #include "base/bind.h"
8 #include "base/compiler_specific.h"
9 #include "base/location.h"
10 #include "base/logging.h"
11 #include "base/mac/bind_objc_block.h"
12 #include "base/mac/scoped_nsobject.h"
13 #include "base/sequenced_task_runner.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/sys_string_conversions.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "components/webp_transcode/webp_decoder.h"
19 #include "net/base/net_errors.h"
20 #include "net/http/http_request_headers.h"
21 #include "net/url_request/url_request.h"
22
23 namespace net {
24 class URLRequest;
25 } // namespace net
sdefresne 2015/03/19 17:06:34 nit: no need for the "// namespace net" for singl
26
27 using namespace webp_transcode;
28
29 namespace {
30
31 // MIME type for WebP images.
32 const char kWebPMimeType[] = "image/webp";
33
34 NSURLResponse* NewImageResponse(NSURLResponse* webp_response,
35 size_t content_length,
36 WebpDecoder::DecodedImageFormat format) {
37 DCHECK(webp_response);
38
39 NSString* mime_type = nil;
40 switch (format) {
41 case WebpDecoder::JPEG:
42 mime_type = @"image/jpeg";
43 break;
44 case WebpDecoder::PNG:
45 mime_type = @"image/png";
46 break;
47 case WebpDecoder::TIFF:
48 mime_type = @"image/tiff";
49 break;
50 case WebpDecoder::DECODED_FORMAT_COUNT:
51 NOTREACHED();
52 break;
53 }
54 DCHECK(mime_type);
55
56 if ([webp_response isKindOfClass:[NSHTTPURLResponse class]]) {
57 NSHTTPURLResponse* http_response =
58 static_cast<NSHTTPURLResponse*>(webp_response);
59 NSMutableDictionary* header_fields = [NSMutableDictionary
60 dictionaryWithDictionary:[http_response allHeaderFields]];
61 [header_fields setObject:[NSString stringWithFormat:@"%zu", content_length]
62 forKey:@"Content-Length"];
63 [header_fields setObject:mime_type forKey:@"Content-Type"];
64 return [[NSHTTPURLResponse alloc] initWithURL:[http_response URL]
65 statusCode:[http_response statusCode]
66 HTTPVersion:@"HTTP/1.1"
67 headerFields:header_fields];
68 } else {
69 return [[NSURLResponse alloc] initWithURL:[webp_response URL]
70 MIMEType:mime_type
71 expectedContentLength:content_length
72 textEncodingName:[webp_response textEncodingName]];
73 }
74 }
75
76 class WebpDecoderDelegate : public WebpDecoder::Delegate {
77 public:
78 WebpDecoderDelegate(id<CRNNetworkClientProtocol> client,
79 const base::Time& request_creation_time,
80 const scoped_refptr<base::TaskRunner>& callback_runner)
81 : underlying_client_([client retain]),
82 callback_task_runner_(callback_runner),
83 request_creation_time_(request_creation_time) {
84 DCHECK(underlying_client_.get());
85 }
86
87 void SetOriginalResponse(
88 const base::scoped_nsobject<NSURLResponse>& response) {
89 original_response_.reset([response retain]);
90 }
91
92 // WebpDecoder::Delegate methods.
93 void OnFinishedDecoding(bool success) override {
94 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
95 [underlying_client_ retain]);
96 if (success) {
97 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
98 [block_client didFinishLoading];
99 }));
100 } else {
101 DLOG(WARNING) << "WebP decoding failed "
102 << base::SysNSStringToUTF8(
103 [[original_response_ URL] absoluteString]);
104 void (^errorBlock)(void) = ^{
105 [block_client didFailWithNSErrorCode:NSURLErrorCannotDecodeContentData
106 netErrorCode:net::ERR_CONTENT_DECODING_FAILED];
107 };
108 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(errorBlock));
109 }
110 }
111
112 void SetImageFeatures(size_t total_size,
113 WebpDecoder::DecodedImageFormat format) override {
114 base::scoped_nsobject<NSURLResponse> imageResponse(
115 NewImageResponse(original_response_, total_size, format));
116 DCHECK(imageResponse);
117 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
118 [underlying_client_ retain]);
119 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
120 [block_client didReceiveResponse:imageResponse];
121 }));
122 }
123
124 void OnDataDecoded(NSData* data) override {
125 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
126 [underlying_client_ retain]);
127 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
128 [block_client didLoadData:data];
129 }));
130 }
131
132 private:
133 ~WebpDecoderDelegate() override {}
134
135 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> underlying_client_;
136 base::scoped_nsobject<NSURLResponse> original_response_;
137 scoped_refptr<base::TaskRunner> callback_task_runner_;
138 base::Time request_creation_time_;
139 };
140
141 } // namespace
142
143 @interface WebPNetworkClient () {
144 scoped_refptr<webp_transcode::WebpDecoder> _webpDecoder;
145 scoped_refptr<WebpDecoderDelegate> _webpDecoderDelegate;
146 scoped_refptr<base::SequencedTaskRunner> _taskRunner;
147 base::Time _requestCreationTime;
148 }
149 @end
150
151 @implementation WebPNetworkClient
152
153 - (instancetype)init {
154 NOTREACHED() << "Use |-initWithTaskRunner:| instead";
155 return nil;
156 }
157
158 - (instancetype)initWithTaskRunner:
159 (const scoped_refptr<base::SequencedTaskRunner>&)runner {
sdefresne 2015/03/19 17:06:34 style: should be 4 space indentation, not 8
160 if (self = [super init]) {
161 DCHECK(runner);
162 _taskRunner = runner;
163 }
164 return self;
165 }
166
167 - (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest {
168 // Append 'image/webp' to the outgoing 'Accept' header.
169 const net::HttpRequestHeaders& headers =
170 nativeRequest->extra_request_headers();
171 std::string acceptHeader;
172 if (headers.GetHeader("Accept", &acceptHeader)) {
173 // Add 'image/webp' if it isn't in the Accept header yet.
174 std::string mimePattern = std::string("*") + kWebPMimeType + "*";
sdefresne 2015/03/19 17:06:34 All those allocations for every native requests ma
175 if (!MatchPattern(acceptHeader, mimePattern)) {
176 acceptHeader += std::string(",") + kWebPMimeType;
177 nativeRequest->SetExtraRequestHeaderByName("Accept", acceptHeader, true);
178 }
179 } else {
180 // All requests should already have an Accept: header, so this case
181 // should never happen outside of unit tests.
182 nativeRequest->SetExtraRequestHeaderByName("Accept", kWebPMimeType, false);
183 }
184 [super didCreateNativeRequest:nativeRequest];
185 }
186
187 - (void)didLoadData:(NSData*)data {
188 if (_webpDecoder.get()) {
189 // |data| is assumed to be immutable.
190 base::scoped_nsobject<NSData> scopedData([data retain]);
191 _taskRunner->PostTask(FROM_HERE, base::Bind(&WebpDecoder::OnDataReceived,
192 _webpDecoder, scopedData));
193 } else {
194 [super didLoadData:data];
195 }
196 }
197
198 - (void)didReceiveResponse:(NSURLResponse*)response {
199 DCHECK(self.underlyingClient);
200 NSString* responseMimeType = [response MIMEType];
201 NSString* webPMimeType =
202 [NSString stringWithCString:kWebPMimeType encoding:NSASCIIStringEncoding];
203 if (responseMimeType &&
204 [responseMimeType caseInsensitiveCompare:webPMimeType] == NSOrderedSame) {
205 _webpDecoderDelegate =
206 new WebpDecoderDelegate(self.underlyingClient, _requestCreationTime,
207 base::ThreadTaskRunnerHandle::Get());
208 _webpDecoder = new webp_transcode::WebpDecoder(_webpDecoderDelegate.get());
209 base::scoped_nsobject<NSURLResponse> scoped_response([response copy]);
210 _taskRunner->PostTask(FROM_HERE,
211 base::Bind(&WebpDecoderDelegate::SetOriginalResponse,
212 _webpDecoderDelegate, scoped_response));
213 // Do not call super here, the WebpDecoderDelegate will update the mime type
214 // and call |-didReceiveResponse:|.
215 } else {
216 // If this isn't a WebP, pass the call up the chain.
217 // TODO(marq): It would be nice if at this point the client could remove
218 // itself from the client stack.
219 [super didReceiveResponse:response];
220 }
221 }
222
223 - (void)didFinishLoading {
224 if (_webpDecoder.get()) {
225 _taskRunner->PostTask(FROM_HERE,
226 base::Bind(&WebpDecoder::Stop, _webpDecoder));
227 } else {
228 [super didFinishLoading];
229 }
230 }
231
232 @end
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698