Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / media_galleries / fileapi / mtp_file_stream_reader.cc
1 // Copyright 2014 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 #include "chrome/browser/media_galleries/fileapi/mtp_file_stream_reader.h"
6
7 #include <algorithm>
8
9 #include "base/numerics/safe_conversions.h"
10 #include "base/platform_file.h"
11 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
12 #include "chrome/browser/media_galleries/fileapi/mtp_device_map_service.h"
13 #include "chrome/browser/media_galleries/fileapi/native_media_file_util.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "net/base/io_buffer.h"
16 #include "net/base/mime_sniffer.h"
17 #include "net/base/net_errors.h"
18 #include "webkit/browser/fileapi/file_system_context.h"
19
20 using webkit_blob::FileStreamReader;
21
22 namespace {
23
24 // Called on the IO thread.
25 MTPDeviceAsyncDelegate* GetMTPDeviceDelegate(
26     const fileapi::FileSystemURL& url) {
27   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
28   return MTPDeviceMapService::GetInstance()->GetMTPDeviceAsyncDelegate(
29       url.filesystem_id());
30 }
31
32 void CallCompletionCallbackWithPlatformFileError(
33     const net::CompletionCallback& callback,
34     base::File::Error file_error) {
35   callback.Run(net::FileErrorToNetError(file_error));
36 }
37
38 void CallInt64CompletionCallbackWithPlatformFileError(
39     const net::Int64CompletionCallback& callback,
40     base::File::Error file_error) {
41   callback.Run(net::FileErrorToNetError(file_error));
42 }
43
44 void ReadBytes(
45     const fileapi::FileSystemURL& url, net::IOBuffer* buf, int64 offset,
46     int buf_len,
47     const MTPDeviceAsyncDelegate::ReadBytesSuccessCallback& success_callback,
48     const net::CompletionCallback& error_callback) {
49   MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url);
50   if (!delegate) {
51     error_callback.Run(net::ERR_FAILED);
52     return;
53   }
54
55   delegate->ReadBytes(
56       url.path(),
57       make_scoped_refptr(buf),
58       offset,
59       buf_len,
60       success_callback,
61       base::Bind(&CallCompletionCallbackWithPlatformFileError, error_callback));
62 }
63
64 }  // namespace
65
66 MTPFileStreamReader::MTPFileStreamReader(
67     fileapi::FileSystemContext* file_system_context,
68     const fileapi::FileSystemURL& url,
69     int64 initial_offset,
70     const base::Time& expected_modification_time,
71     bool do_media_header_validation)
72     : file_system_context_(file_system_context),
73       url_(url),
74       current_offset_(initial_offset),
75       expected_modification_time_(expected_modification_time),
76       media_header_validated_(!do_media_header_validation),
77       weak_factory_(this) {
78 }
79
80 MTPFileStreamReader::~MTPFileStreamReader() {
81 }
82
83 int MTPFileStreamReader::Read(net::IOBuffer* buf, int buf_len,
84                               const net::CompletionCallback& callback) {
85   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
86
87   MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url_);
88   if (!delegate)
89     return net::ERR_FAILED;
90
91   if (!media_header_validated_) {
92     scoped_refptr<net::IOBuffer> header_buf;
93     int header_buf_len = 0;
94
95     if (current_offset_ == 0 && buf_len >= net::kMaxBytesToSniff) {
96       // If requested read includes all the header bytes, we read directly to
97       // the original buffer, and validate the header bytes within that.
98       header_buf = buf;
99       header_buf_len = buf_len;
100     } else {
101       // Otherwise, make a special request for the header.
102       header_buf = new net::IOBuffer(net::kMaxBytesToSniff);
103       header_buf_len = net::kMaxBytesToSniff;
104     }
105
106     ReadBytes(url_, header_buf, 0, header_buf_len,
107               base::Bind(&MTPFileStreamReader::FinishValidateMediaHeader,
108                          weak_factory_.GetWeakPtr(), header_buf,
109                          make_scoped_refptr(buf), buf_len, callback),
110               callback);
111     return net::ERR_IO_PENDING;
112   }
113
114   ReadBytes(url_, buf, current_offset_, buf_len,
115             base::Bind(&MTPFileStreamReader::FinishRead,
116                        weak_factory_.GetWeakPtr(), callback),
117             callback);
118
119   return net::ERR_IO_PENDING;
120 }
121
122 int64 MTPFileStreamReader::GetLength(
123     const net::Int64CompletionCallback& callback) {
124   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
125
126   MTPDeviceAsyncDelegate* delegate = GetMTPDeviceDelegate(url_);
127   if (!delegate)
128     return net::ERR_FAILED;
129
130   delegate->GetFileInfo(
131         url_.path(),
132         base::Bind(&MTPFileStreamReader::FinishGetLength,
133                    weak_factory_.GetWeakPtr(), callback),
134         base::Bind(&CallInt64CompletionCallbackWithPlatformFileError,
135                    callback));
136
137   return net::ERR_IO_PENDING;
138 }
139
140 void MTPFileStreamReader::FinishValidateMediaHeader(
141     net::IOBuffer* header_buf,
142     net::IOBuffer* buf, int buf_len,
143     const net::CompletionCallback& callback,
144     const base::File::Info& file_info,
145     int header_bytes_read) {
146   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
147   DCHECK_GE(header_bytes_read, 0);
148   base::File::Error error = NativeMediaFileUtil::BufferIsMediaHeader(
149       header_buf, header_bytes_read);
150   if (error != base::File::FILE_OK) {
151     CallCompletionCallbackWithPlatformFileError(callback, error);
152     return;
153   }
154
155   media_header_validated_ = true;
156
157   // Finish the read immediately if we've already finished reading into the
158   // originally requested buffer.
159   if (header_buf == buf)
160     return FinishRead(callback, file_info, header_bytes_read);
161
162   // Header buffer isn't the same as the original read buffer. Make a separate
163   // request for that.
164   ReadBytes(url_, buf, current_offset_, buf_len,
165             base::Bind(&MTPFileStreamReader::FinishRead,
166                        weak_factory_.GetWeakPtr(), callback),
167             callback);
168 }
169
170 void MTPFileStreamReader::FinishRead(const net::CompletionCallback& callback,
171                                      const base::File::Info& file_info,
172                                      int bytes_read) {
173   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
174
175   if (!VerifySnapshotTime(expected_modification_time_, file_info)) {
176     callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
177     return;
178   }
179
180   DCHECK_GE(bytes_read, 0);
181   current_offset_ += bytes_read;
182   callback.Run(bytes_read);
183 }
184
185 void MTPFileStreamReader::FinishGetLength(
186     const net::Int64CompletionCallback& callback,
187     const base::File::Info& file_info) {
188   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
189
190   if (!VerifySnapshotTime(expected_modification_time_, file_info)) {
191     callback.Run(net::ERR_UPLOAD_FILE_CHANGED);
192     return;
193   }
194
195   callback.Run(file_info.size);
196 }