Extract code handling PrinterProviderAPI from PrintPreviewHandler
[chromium-blink-merge.git] / ios / chrome / browser / net / image_fetcher.mm
blob89f59c7dc138c406529002d615a070cc405ae5ad
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/chrome/browser/net/image_fetcher.h"
7 #import <Foundation/Foundation.h>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/mac/scoped_nsobject.h"
12 #include "base/task_runner.h"
13 #include "components/webp_transcode/webp_decoder.h"
14 #include "ios/web/public/web_thread.h"
15 #include "net/base/load_flags.h"
16 #include "net/http/http_response_headers.h"
17 #include "net/url_request/url_fetcher.h"
18 #include "net/url_request/url_request_context_getter.h"
20 namespace {
22 class WebpDecoderDelegate : public webp_transcode::WebpDecoder::Delegate {
23  public:
24   NSData* data() const { return decoded_image_; }
26   // WebpDecoder::Delegate methods
27   void OnFinishedDecoding(bool success) override {
28     if (!success)
29       decoded_image_.reset();
30   }
31   void SetImageFeatures(
32       size_t total_size,
33       webp_transcode::WebpDecoder::DecodedImageFormat format) override {
34     decoded_image_.reset([[NSMutableData alloc] initWithCapacity:total_size]);
35   }
36   void OnDataDecoded(NSData* data) override {
37     DCHECK(decoded_image_);
38     [decoded_image_ appendData:data];
39   }
40  private:
41   ~WebpDecoderDelegate() override {}
42   base::scoped_nsobject<NSMutableData> decoded_image_;
45 // Content-type header for WebP images.
46 static const char kWEBPMimeType[] = "image/webp";
48 // Returns a NSData object containing the decoded image.
49 // Returns nil in case of failure.
50 base::scoped_nsobject<NSData> DecodeWebpImage(
51     const base::scoped_nsobject<NSData>& webp_image) {
52   scoped_refptr<WebpDecoderDelegate> delegate(new WebpDecoderDelegate);
53   scoped_refptr<webp_transcode::WebpDecoder> decoder(
54       new webp_transcode::WebpDecoder(delegate.get()));
55   decoder->OnDataReceived(webp_image);
56   DLOG_IF(ERROR, !delegate->data()) << "WebP image decoding failed.";
57   return base::scoped_nsobject<NSData>([delegate->data() retain]);
60 }  // namespace
62 namespace image_fetcher {
64 ImageFetcher::ImageFetcher(const scoped_refptr<base::TaskRunner>& task_runner)
65     : request_context_getter_(nullptr),
66       task_runner_(task_runner),
67       weak_factory_(this) {
68   DCHECK(task_runner_.get());
71 ImageFetcher::~ImageFetcher() {
72   // Delete all the entries in the |downloads_in_progress_| map.  This will in
73   // turn cancel all of the requests.
74   for (const auto& pair : downloads_in_progress_) {
75     [pair.second release];
76     delete pair.first;
77   }
80 void ImageFetcher::StartDownload(
81     const GURL& url,
82     ImageFetchedCallback callback,
83     const std::string& referrer,
84     net::URLRequest::ReferrerPolicy referrer_policy) {
85   DCHECK(request_context_getter_.get());
86   net::URLFetcher* fetcher = net::URLFetcher::Create(url,
87                                                      net::URLFetcher::GET,
88                                                      this);
89   downloads_in_progress_[fetcher] = [callback copy];
90   fetcher->SetLoadFlags(
91       net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES |
92       net::LOAD_DO_NOT_SEND_AUTH_DATA);
93   fetcher->SetRequestContext(request_context_getter_.get());
94   fetcher->SetReferrer(referrer);
95   fetcher->SetReferrerPolicy(referrer_policy);
96   fetcher->Start();
99 void ImageFetcher::StartDownload(
100     const GURL& url, ImageFetchedCallback callback) {
101   ImageFetcher::StartDownload(
102       url, callback, std::string(), net::URLRequest::NEVER_CLEAR_REFERRER);
105 // Delegate callback that is called when URLFetcher completes.  If the image
106 // was fetched successfully, creates a new NSData and returns it to the
107 // callback, otherwise returns nil to the callback.
108 void ImageFetcher::OnURLFetchComplete(const net::URLFetcher* fetcher) {
109   if (downloads_in_progress_.find(fetcher) == downloads_in_progress_.end()) {
110     LOG(ERROR) << "Received callback for unknown URLFetcher " << fetcher;
111     return;
112   }
114   // Ensures that |fetcher| will be deleted in the event of early return.
115   scoped_ptr<const net::URLFetcher> fetcher_deleter(fetcher);
117   // Retrieves the callback and ensures that it will be deleted in the event
118   // of early return.
119   base::mac::ScopedBlock<ImageFetchedCallback> callback(
120       downloads_in_progress_[fetcher]);
122   // Remove |fetcher| from the map.
123   downloads_in_progress_.erase(fetcher);
125   // Make sure the request was successful. For "data" requests, the response
126   // code has no meaning, because there is no actual server (data is encoded
127   // directly in the URL). In that case, set the response code to 200 (OK).
128   const GURL& original_url = fetcher->GetOriginalURL();
129   const int http_response_code = original_url.SchemeIs("data") ?
130       200 : fetcher->GetResponseCode();
131   if (http_response_code != 200) {
132     (callback.get())(original_url, http_response_code, nil);
133     return;
134   }
136   std::string response;
137   if (!fetcher->GetResponseAsString(&response)) {
138     (callback.get())(original_url, http_response_code, nil);
139     return;
140   }
142   // Create a NSData from the returned data and notify the callback.
143   base::scoped_nsobject<NSData> data([[NSData alloc]
144       initWithBytes:reinterpret_cast<const unsigned char*>(response.data())
145              length:response.size()]);
147   if (fetcher->GetResponseHeaders()) {
148     std::string mime_type;
149     fetcher->GetResponseHeaders()->GetMimeType(&mime_type);
150     if (mime_type == kWEBPMimeType) {
151       base::PostTaskAndReplyWithResult(task_runner_.get(),
152                                        FROM_HERE,
153                                        base::Bind(&DecodeWebpImage, data),
154                                        base::Bind(&ImageFetcher::RunCallback,
155                                                   weak_factory_.GetWeakPtr(),
156                                                   callback,
157                                                   original_url,
158                                                   http_response_code));
159       return;
160     }
161   }
162   (callback.get())(original_url, http_response_code, data);
165 void ImageFetcher::RunCallback(
166     const base::mac::ScopedBlock<ImageFetchedCallback>& callback,
167     const GURL& url,
168     int http_response_code,
169     NSData* data) {
170   (callback.get())(url, http_response_code, data);
173 void ImageFetcher::SetRequestContextGetter(
174     const scoped_refptr<net::URLRequestContextGetter>& request_context_getter) {
175   request_context_getter_ = request_context_getter;
178 }  // namespace image_fetcher