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