11320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Copyright 2014 The Chromium Authors. All rights reserved.
21320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Use of this source code is governed by a BSD-style license that can be
31320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// found in the LICENSE file.
41320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
51320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/chromeos/fileapi/external_file_url_request_job.h"
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <algorithm>
81320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include <vector>
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/bind.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/logging.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/memory/ref_counted.h"
131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/browser_process.h"
141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/chromeos/drive/file_system_util.h"
151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/chromeos/fileapi/external_file_url_util.h"
161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/extensions/api/file_handlers/mime_util.h"
171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/browser/profiles/profile_manager.h"
181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "chrome/common/url_constants.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/browser_thread.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/storage_partition.h"
211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/base/net_errors.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/http/http_byte_range.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/http/http_request_headers.h"
241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/http/http_response_info.h"
251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/http/http_util.h"
261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/url_request/url_request.h"
271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "net/url_request/url_request_status.h"
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/file_system_backend.h"
291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/file_system_context.h"
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "storage/browser/fileapi/file_system_operation_runner.h"
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciusing content::BrowserThread;
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace chromeos {
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccinamespace {
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kMimeTypeForRFC822[] = "message/rfc822";
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst char kMimeTypeForMHTML[] = "multipart/related";
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Helper for obtaining FileSystemContext, FileSystemURL, and mime type on the
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// UI thread.
421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass URLHelper {
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // The scoped pointer to control lifetime of the instance itself. The pointer
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // is passed to callback functions and binds the lifetime of the instance to
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // the callback's lifetime.
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  typedef scoped_ptr<URLHelper> Lifetime;
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  URLHelper(void* profile_id,
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            const GURL& url,
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            const ExternalFileURLRequestJob::HelperCallback& callback)
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      : profile_id_(profile_id), url_(url), callback_(callback) {
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_CURRENTLY_ON(BrowserThread::IO);
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Lifetime lifetime(this);
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BrowserThread::PostTask(BrowserThread::UI,
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            FROM_HERE,
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            base::Bind(&URLHelper::RunOnUIThread,
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       base::Unretained(this),
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       base::Passed(&lifetime)));
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci private:
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void RunOnUIThread(Lifetime lifetime) {
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_CURRENTLY_ON(BrowserThread::UI);
651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    Profile* const profile = reinterpret_cast<Profile*>(profile_id_);
661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (!g_browser_process->profile_manager()->IsValidProfile(profile)) {
671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ReplyResult(net::ERR_FAILED);
681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content::StoragePartition* const storage =
711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        content::BrowserContext::GetStoragePartitionForSite(profile, url_);
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(storage);
731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_refptr<storage::FileSystemContext> context =
751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        storage->GetFileSystemContext();
761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(context.get());
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Obtain the absolute path in the file system.
791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::FilePath virtual_path = ExternalFileURLToVirtualPath(url_);
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Obtain the file system URL.
821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // TODO(hirono): After removing MHTML support, stop to use the special
831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // drive: scheme and use filesystem: URL directly.  crbug.com/415455
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    file_system_url_ = context->CreateCrackedFileSystemURL(
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        GURL(std::string(chrome::kExternalFileScheme) + ":"),
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        storage::kFileSystemTypeExternal,
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        virtual_path);
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Check if the obtained path providing external file URL or not.
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (FileSystemURLToExternalFileURL(file_system_url_).is_empty()) {
911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ReplyResult(net::ERR_INVALID_URL);
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return;
931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    file_system_context_ = context;
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    extensions::app_file_handler_util::GetMimeTypeForLocalPath(
981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        profile,
991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        file_system_url_.path(),
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        base::Bind(&URLHelper::OnGotMimeTypeOnUIThread,
1011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Unretained(this),
1021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                   base::Passed(&lifetime)));
1031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void OnGotMimeTypeOnUIThread(Lifetime lifetime,
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                               const std::string& mime_type) {
1071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_CURRENTLY_ON(BrowserThread::UI);
1081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    mime_type_ = mime_type;
1091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (mime_type_ == kMimeTypeForRFC822)
1111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      mime_type_ = kMimeTypeForMHTML;
1121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    ReplyResult(net::OK);
1141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void ReplyResult(net::Error error) {
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_CURRENTLY_ON(BrowserThread::UI);
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    BrowserThread::PostTask(BrowserThread::IO,
1201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            FROM_HERE,
1211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                            base::Bind(callback_,
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       error,
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       file_system_context_,
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       file_system_url_,
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       mime_type_));
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void* const profile_id_;
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const GURL url_;
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const ExternalFileURLRequestJob::HelperCallback callback_;
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_refptr<storage::FileSystemContext> file_system_context_;
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  storage::FileSystemURL file_system_url_;
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string mime_type_;
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DISALLOW_COPY_AND_ASSIGN(URLHelper);
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
1371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace
1391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciExternalFileURLRequestJob::ExternalFileURLRequestJob(
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    void* profile_id,
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::URLRequest* request,
1431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::NetworkDelegate* network_delegate)
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    : net::URLRequestJob(request, network_delegate),
1451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      profile_id_(profile_id),
1461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      remaining_bytes_(0),
1471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      weak_ptr_factory_(this) {
1481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::SetExtraRequestHeaders(
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const net::HttpRequestHeaders& headers) {
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  std::string range_header;
1531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
1541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // Note: We only support single range requests.
1551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    std::vector<net::HttpByteRange> ranges;
1561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if (net::HttpUtil::ParseRangeHeader(range_header, &ranges) &&
1571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        ranges.size() == 1) {
1581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      byte_range_ = ranges[0];
1591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    } else {
1601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      // Failed to parse Range: header, so notify the error.
1611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED,
1621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                       net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
1631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    }
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::Start() {
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DVLOG(1) << "Starting request";
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_CURRENTLY_ON(BrowserThread::IO);
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(!stream_reader_);
1711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // We only support GET request.
1731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (request()->method() != "GET") {
1741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    LOG(WARNING) << "Failed to start request: " << request()->method()
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 << " method is not supported";
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
1771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           net::ERR_METHOD_NOT_SUPPORTED));
1781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Check if the scheme is correct.
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!request()->url().SchemeIs(chrome::kExternalFileScheme)) {
1831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           net::ERR_INVALID_URL));
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Owned by itself.
1891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  new URLHelper(profile_id_,
1901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                request()->url(),
1911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                base::Bind(&ExternalFileURLRequestJob::OnHelperResultObtained,
1921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                           weak_ptr_factory_.GetWeakPtr()));
1931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
1941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::OnHelperResultObtained(
1961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    net::Error error,
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const scoped_refptr<storage::FileSystemContext>& file_system_context,
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const storage::FileSystemURL& file_system_url,
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const std::string& mime_type) {
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK_CURRENTLY_ON(BrowserThread::IO);
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (error != net::OK) {
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(
2041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        net::URLRequestStatus(net::URLRequestStatus::FAILED, error));
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(file_system_context.get());
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file_system_context_ = file_system_context;
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file_system_url_ = file_system_url;
2111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  mime_type_ = mime_type;
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Check if the entry has a redirect URL.
2141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file_system_context_->external_backend()->GetRedirectURLForContents(
2151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      file_system_url_,
2161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ExternalFileURLRequestJob::OnRedirectURLObtained,
2171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
2181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::OnRedirectURLObtained(
2211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const GURL& redirect_url) {
2221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  redirect_url_ = redirect_url;
2241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!redirect_url_.is_empty()) {
2251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyHeadersComplete();
2261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Obtain file system context.
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file_system_context_->operation_runner()->GetMetadata(
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      file_system_url_,
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ExternalFileURLRequestJob::OnFileInfoObtained,
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::OnFileInfoObtained(
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    base::File::Error result,
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    const base::File::Info& file_info) {
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result == base::File::FILE_ERROR_NOT_FOUND) {
2421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           net::ERR_FILE_NOT_FOUND));
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result != base::File::FILE_OK || file_info.is_directory ||
2481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      file_info.size < 0) {
2491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(
2501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_FAILED));
2511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Compute content size.
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!byte_range_.ComputeBounds(file_info.size)) {
2561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(net::URLRequestStatus(
2571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        net::URLRequestStatus::FAILED, net::ERR_REQUEST_RANGE_NOT_SATISFIABLE));
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int64 offset = byte_range_.first_byte_position();
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int64 size =
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      byte_range_.last_byte_position() + 1 - byte_range_.first_byte_position();
2631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  set_expected_content_size(size);
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  remaining_bytes_ = size;
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Create file stream reader.
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stream_reader_ = file_system_context_->CreateFileStreamReader(
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      file_system_url_, offset, size, base::Time());
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (!stream_reader_) {
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           net::ERR_FILE_NOT_FOUND));
2721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return;
2731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
2741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  NotifyHeadersComplete();
2761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::Kill() {
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  stream_reader_.reset();
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  file_system_context_ = NULL;
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  net::URLRequestJob::Kill();
2841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  weak_ptr_factory_.InvalidateWeakPtrs();
2851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ExternalFileURLRequestJob::GetMimeType(std::string* mime_type) const {
2881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  mime_type->assign(mime_type_);
2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return !mime_type->empty();
2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ExternalFileURLRequestJob::IsRedirectResponse(GURL* location,
2941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                                   int* http_status_code) {
2951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (redirect_url_.is_empty())
2971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
2981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Redirect a hosted document.
3001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  *location = redirect_url_;
3011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int kHttpFound = 302;
3021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  *http_status_code = kHttpFound;
3031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
3041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccibool ExternalFileURLRequestJob::ReadRawData(net::IOBuffer* buf,
3071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            int buf_size,
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                            int* bytes_read) {
3091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(stream_reader_);
3111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (remaining_bytes_ == 0) {
3131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    *bytes_read = 0;
3141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return true;
3151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  const int result = stream_reader_->Read(
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      buf,
3191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      std::min<int64>(buf_size, remaining_bytes_),
3201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      base::Bind(&ExternalFileURLRequestJob::OnReadCompleted,
3211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                 weak_ptr_factory_.GetWeakPtr()));
3221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result == net::ERR_IO_PENDING) {
3241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // The data is not yet available.
3251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
3261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (result < 0) {
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    // An error occurs.
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, result));
3311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return false;
3321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Reading has been finished immediately.
3351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  *bytes_read = result;
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  remaining_bytes_ -= result;
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  return true;
3381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciExternalFileURLRequestJob::~ExternalFileURLRequestJob() {
3411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tuccivoid ExternalFileURLRequestJob::OnReadCompleted(int read_result) {
3441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
3451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (read_result < 0) {
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK_NE(read_result, net::ERR_IO_PENDING);
3481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    NotifyDone(
3491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        net::URLRequestStatus(net::URLRequestStatus::FAILED, read_result));
3501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  remaining_bytes_ -= read_result;
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  SetStatus(net::URLRequestStatus());  // Clear the IO_PENDING status.
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  NotifyReadComplete(read_result);
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
3561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}  // namespace chromeos
358