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

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: Review comments 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 }
26
27 using namespace webp_transcode;
28
29 namespace {
30
31 // MIME type for WebP images.
32 const char kWebPMimeType[] = "image/webp";
33 NSString* const kNSWebPMimeType = @"image/webp";
34
35 NSURLResponse* NewImageResponse(NSURLResponse* webp_response,
36 size_t content_length,
37 WebpDecoder::DecodedImageFormat format) {
38 DCHECK(webp_response);
39
40 NSString* mime_type = nil;
41 switch (format) {
42 case WebpDecoder::JPEG:
43 mime_type = @"image/jpeg";
44 break;
45 case WebpDecoder::PNG:
46 mime_type = @"image/png";
47 break;
48 case WebpDecoder::TIFF:
49 mime_type = @"image/tiff";
50 break;
51 case WebpDecoder::DECODED_FORMAT_COUNT:
52 NOTREACHED();
53 break;
54 }
55 DCHECK(mime_type);
56
57 if ([webp_response isKindOfClass:[NSHTTPURLResponse class]]) {
58 NSHTTPURLResponse* http_response =
59 static_cast<NSHTTPURLResponse*>(webp_response);
60 NSMutableDictionary* header_fields = [NSMutableDictionary
61 dictionaryWithDictionary:[http_response allHeaderFields]];
62 [header_fields setObject:[NSString stringWithFormat:@"%zu", content_length]
63 forKey:@"Content-Length"];
64 [header_fields setObject:mime_type forKey:@"Content-Type"];
65 return [[NSHTTPURLResponse alloc] initWithURL:[http_response URL]
66 statusCode:[http_response statusCode]
67 HTTPVersion:@"HTTP/1.1"
68 headerFields:header_fields];
69 } else {
70 return [[NSURLResponse alloc] initWithURL:[webp_response URL]
71 MIMEType:mime_type
72 expectedContentLength:content_length
73 textEncodingName:[webp_response textEncodingName]];
74 }
75 }
76
77 class WebpDecoderDelegate : public WebpDecoder::Delegate {
78 public:
79 WebpDecoderDelegate(id<CRNNetworkClientProtocol> client,
80 const base::Time& request_creation_time,
81 const scoped_refptr<base::TaskRunner>& callback_runner)
82 : underlying_client_([client retain]),
83 callback_task_runner_(callback_runner),
84 request_creation_time_(request_creation_time) {
85 DCHECK(underlying_client_.get());
86 }
87
88 void SetOriginalResponse(
89 const base::scoped_nsobject<NSURLResponse>& response) {
90 original_response_.reset([response retain]);
91 }
92
93 // WebpDecoder::Delegate methods.
94 void OnFinishedDecoding(bool success) override {
95 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
96 [underlying_client_ retain]);
97 if (success) {
98 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
99 [block_client didFinishLoading];
100 }));
101 } else {
102 DLOG(WARNING) << "WebP decoding failed "
103 << base::SysNSStringToUTF8(
104 [[original_response_ URL] absoluteString]);
105 void (^errorBlock)(void) = ^{
106 [block_client didFailWithNSErrorCode:NSURLErrorCannotDecodeContentData
107 netErrorCode:net::ERR_CONTENT_DECODING_FAILED];
108 };
109 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(errorBlock));
110 }
111 }
112
113 void SetImageFeatures(size_t total_size,
114 WebpDecoder::DecodedImageFormat format) override {
115 base::scoped_nsobject<NSURLResponse> imageResponse(
116 NewImageResponse(original_response_, total_size, format));
117 DCHECK(imageResponse);
118 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
119 [underlying_client_ retain]);
120 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
121 [block_client didReceiveResponse:imageResponse];
122 }));
123 }
124
125 void OnDataDecoded(NSData* data) override {
126 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> block_client(
127 [underlying_client_ retain]);
128 callback_task_runner_->PostTask(FROM_HERE, base::BindBlock(^{
129 [block_client didLoadData:data];
130 }));
131 }
132
133 private:
134 ~WebpDecoderDelegate() override {}
135
136 base::scoped_nsprotocol<id<CRNNetworkClientProtocol>> underlying_client_;
137 base::scoped_nsobject<NSURLResponse> original_response_;
138 scoped_refptr<base::TaskRunner> callback_task_runner_;
139 base::Time request_creation_time_;
140 };
141
142 } // namespace
143
144 @interface WebPNetworkClient () {
145 scoped_refptr<webp_transcode::WebpDecoder> _webpDecoder;
146 scoped_refptr<WebpDecoderDelegate> _webpDecoderDelegate;
147 scoped_refptr<base::SequencedTaskRunner> _taskRunner;
148 base::Time _requestCreationTime;
149 }
150 @end
151
152 @implementation WebPNetworkClient
153
154 - (instancetype)init {
155 NOTREACHED() << "Use |-initWithTaskRunner:| instead";
156 return nil;
157 }
158
159 - (instancetype)initWithTaskRunner:
160 (const scoped_refptr<base::SequencedTaskRunner>&)runner {
161 if (self = [super init]) {
162 DCHECK(runner);
163 _taskRunner = runner;
164 }
165 return self;
166 }
167
168 - (void)didCreateNativeRequest:(net::URLRequest*)nativeRequest {
169 // Append 'image/webp' to the outgoing 'Accept' header.
170 const net::HttpRequestHeaders& headers =
171 nativeRequest->extra_request_headers();
172 std::string acceptHeader;
173 if (headers.GetHeader("Accept", &acceptHeader)) {
174 // Add 'image/webp' if it isn't in the Accept header yet.
175 if (acceptHeader.find(kWebPMimeType) == std::string::npos) {
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 if (responseMimeType &&
202 [responseMimeType caseInsensitiveCompare:kNSWebPMimeType] ==
203 NSOrderedSame) {
204 _webpDecoderDelegate =
205 new WebpDecoderDelegate(self.underlyingClient, _requestCreationTime,
206 base::ThreadTaskRunnerHandle::Get());
207 _webpDecoder = new webp_transcode::WebpDecoder(_webpDecoderDelegate.get());
208 base::scoped_nsobject<NSURLResponse> scoped_response([response copy]);
209 _taskRunner->PostTask(FROM_HERE,
210 base::Bind(&WebpDecoderDelegate::SetOriginalResponse,
211 _webpDecoderDelegate, scoped_response));
212 // Do not call super here, the WebpDecoderDelegate will update the mime type
213 // and call |-didReceiveResponse:|.
214 } else {
215 // If this isn't a WebP, pass the call up the chain.
216 // TODO(marq): It would be nice if at this point the client could remove
217 // itself from the client stack.
218 [super didReceiveResponse:response];
219 }
220 }
221
222 - (void)didFinishLoading {
223 if (_webpDecoder.get()) {
224 _taskRunner->PostTask(FROM_HERE,
225 base::Bind(&WebpDecoder::Stop, _webpDecoder));
226 } else {
227 [super didFinishLoading];
228 }
229 }
230
231 @end
OLDNEW
« no previous file with comments | « components/webp_transcode/webp_network_client.h ('k') | components/webp_transcode/webp_network_client_factory.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698