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

Side by Side Diff: webkit/plugins/npapi/plugin_stream.cc

Issue 19761007: Move NPAPI implementation out of webkit/plugins/npapi and into content. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: fix mac Created 7 years, 5 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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.
4
5 // TODO : Support NP_ASFILEONLY mode
6 // TODO : Support NP_SEEK mode
7 // TODO : Support SEEKABLE=true in NewStream
8
9 #include "webkit/plugins/npapi/plugin_stream.h"
10
11 #include <algorithm>
12
13 #include "base/bind.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/string_util.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "net/base/mime_util.h"
18 #include "url/gurl.h"
19 #include "webkit/plugins/npapi/plugin_instance.h"
20
21 namespace webkit {
22 namespace npapi {
23
24 PluginStream::PluginStream(
25 PluginInstance* instance,
26 const char* url,
27 bool need_notify,
28 void* notify_data)
29 : instance_(instance),
30 notify_needed_(need_notify),
31 notify_data_(notify_data),
32 close_on_write_data_(false),
33 requested_plugin_mode_(NP_NORMAL),
34 opened_(false),
35 data_offset_(0),
36 seekable_stream_(false) {
37 memset(&stream_, 0, sizeof(stream_));
38 stream_.url = base::strdup(url);
39 ResetTempFileHandle();
40 ResetTempFileName();
41 }
42
43 PluginStream::~PluginStream() {
44 // always close our temporary files.
45 CloseTempFile();
46 free(const_cast<char*>(stream_.url));
47 }
48
49 void PluginStream::UpdateUrl(const char* url) {
50 DCHECK(!opened_);
51 free(const_cast<char*>(stream_.url));
52 stream_.url = base::strdup(url);
53 pending_redirect_url_.clear();
54 }
55
56 bool PluginStream::Open(const std::string& mime_type,
57 const std::string& headers,
58 uint32 length,
59 uint32 last_modified,
60 bool request_is_seekable) {
61 headers_ = headers;
62 NPP id = instance_->npp();
63 stream_.end = length;
64 stream_.lastmodified = last_modified;
65 stream_.pdata = 0;
66 stream_.ndata = id->ndata;
67 stream_.notifyData = notify_data_;
68 if (!headers_.empty())
69 stream_.headers = headers_.c_str();
70
71 bool seekable_stream = false;
72 if (request_is_seekable) {
73 std::string headers_lc = StringToLowerASCII(headers);
74 if (headers_lc.find("accept-ranges: bytes") != std::string::npos) {
75 seekable_stream = true;
76 }
77 }
78
79 const char* char_mime_type = "application/x-unknown-content-type";
80 std::string temp_mime_type;
81 if (!mime_type.empty()) {
82 char_mime_type = mime_type.c_str();
83 } else {
84 GURL gurl(stream_.url);
85
86 base::FilePath path = base::FilePath::FromUTF8Unsafe(gurl.path());
87 if (net::GetMimeTypeFromFile(path, &temp_mime_type))
88 char_mime_type = temp_mime_type.c_str();
89 }
90
91 // Silverlight expects a valid mime type
92 DCHECK_NE(0U, strlen(char_mime_type));
93 NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type,
94 &stream_, seekable_stream,
95 &requested_plugin_mode_);
96 if (err != NPERR_NO_ERROR) {
97 Notify(err);
98 return false;
99 }
100
101 opened_ = true;
102
103 if (requested_plugin_mode_ == NP_SEEK) {
104 seekable_stream_ = true;
105 }
106 // If the plugin has requested certain modes, then we need a copy
107 // of this file on disk. Open it and save it as we go.
108 if (RequestedPluginModeIsAsFile()) {
109 if (OpenTempFile() == false) {
110 return false;
111 }
112 }
113
114 mime_type_ = char_mime_type;
115 return true;
116 }
117
118 int PluginStream::Write(const char* buffer, const int length,
119 int data_offset) {
120 // There may be two streams to write to - the plugin and the file.
121 // It is unclear what to do if we cannot write to both. The rules of
122 // this function are that the plugin must consume at least as many
123 // bytes as returned by the WriteReady call. So, we will attempt to
124 // write that many to both streams. If we can't write that many bytes
125 // to each stream, we'll return failure.
126
127 DCHECK(opened_);
128 if (WriteToFile(buffer, length) &&
129 WriteToPlugin(buffer, length, data_offset)) {
130 return length;
131 }
132
133 return -1;
134 }
135
136 bool PluginStream::WriteToFile(const char* buf, size_t length) {
137 // For ASFILEONLY, ASFILE, and SEEK modes, we need to write
138 // to the disk
139 if (TempFileIsValid() && RequestedPluginModeIsAsFile()) {
140 size_t totalBytesWritten = 0, bytes;
141 do {
142 bytes = WriteBytes(buf, length);
143 totalBytesWritten += bytes;
144 } while (bytes > 0U && totalBytesWritten < length);
145
146 if (totalBytesWritten != length) {
147 return false;
148 }
149 }
150
151 return true;
152 }
153
154 bool PluginStream::WriteToPlugin(const char* buf, const int length,
155 const int data_offset) {
156 // For NORMAL and ASFILE modes, we send the data to the plugin now
157 if (requested_plugin_mode_ != NP_NORMAL &&
158 requested_plugin_mode_ != NP_ASFILE &&
159 requested_plugin_mode_ != NP_SEEK) {
160 return true;
161 }
162
163 int written = TryWriteToPlugin(buf, length, data_offset);
164 if (written == -1)
165 return false;
166
167 if (written < length) {
168 // Buffer the remaining data.
169 size_t remaining = length - written;
170 size_t previous_size = delivery_data_.size();
171 delivery_data_.resize(previous_size + remaining);
172 data_offset_ = data_offset;
173 memcpy(&delivery_data_[previous_size], buf + written, remaining);
174 base::MessageLoop::current()->PostTask(
175 FROM_HERE, base::Bind(&PluginStream::OnDelayDelivery, this));
176 }
177
178 return true;
179 }
180
181 void PluginStream::OnDelayDelivery() {
182 // It is possible that the plugin stream may have closed before the task
183 // was hit.
184 if (!opened_)
185 return;
186
187 int size = static_cast<int>(delivery_data_.size());
188 int written = TryWriteToPlugin(&delivery_data_.front(), size, data_offset_);
189 if (written > 0) {
190 // Remove the data that we already wrote.
191 delivery_data_.erase(delivery_data_.begin(),
192 delivery_data_.begin() + written);
193 }
194 }
195
196 int PluginStream::TryWriteToPlugin(const char* buf, const int length,
197 const int data_offset) {
198 int byte_offset = 0;
199
200 if (data_offset > 0)
201 data_offset_ = data_offset;
202
203 while (byte_offset < length) {
204 int bytes_remaining = length - byte_offset;
205 int bytes_to_write = instance_->NPP_WriteReady(&stream_);
206 if (bytes_to_write > bytes_remaining)
207 bytes_to_write = bytes_remaining;
208
209 if (bytes_to_write == 0)
210 return byte_offset;
211
212 int bytes_consumed = instance_->NPP_Write(
213 &stream_, data_offset_, bytes_to_write,
214 const_cast<char*>(buf + byte_offset));
215 if (bytes_consumed < 0) {
216 // The plugin failed, which means that we need to close the stream.
217 Close(NPRES_NETWORK_ERR);
218 return -1;
219 }
220 if (bytes_consumed == 0) {
221 // The plugin couldn't take all of the data now.
222 return byte_offset;
223 }
224
225 // The plugin might report more that we gave it.
226 bytes_consumed = std::min(bytes_consumed, bytes_to_write);
227
228 data_offset_ += bytes_consumed;
229 byte_offset += bytes_consumed;
230 }
231
232 if (close_on_write_data_)
233 Close(NPRES_DONE);
234
235 return length;
236 }
237
238 bool PluginStream::Close(NPReason reason) {
239 if (opened_ == true) {
240 opened_ = false;
241
242 if (delivery_data_.size()) {
243 if (reason == NPRES_DONE) {
244 // There is more data to be streamed, don't destroy the stream now.
245 close_on_write_data_ = true;
246 return true;
247 } else {
248 // Stop any pending data from being streamed
249 delivery_data_.resize(0);
250 }
251 }
252
253 // If we have a temp file, be sure to close it.
254 // Also, allow the plugin to access it now.
255 if (TempFileIsValid()) {
256 CloseTempFile();
257 if (reason == NPRES_DONE)
258 WriteAsFile();
259 }
260
261 if (stream_.ndata != NULL) {
262 // Stream hasn't been closed yet.
263 NPError err = instance_->NPP_DestroyStream(&stream_, reason);
264 DCHECK(err == NPERR_NO_ERROR);
265 }
266 }
267
268 Notify(reason);
269 return true;
270 }
271
272 WebPluginResourceClient* PluginStream::AsResourceClient() {
273 return NULL;
274 }
275
276 void PluginStream::Notify(NPReason reason) {
277 if (notify_needed_) {
278 instance_->NPP_URLNotify(stream_.url, reason, notify_data_);
279 notify_needed_ = false;
280 }
281 }
282
283 bool PluginStream::RequestedPluginModeIsAsFile() const {
284 return (requested_plugin_mode_ == NP_ASFILE ||
285 requested_plugin_mode_ == NP_ASFILEONLY);
286 }
287
288 } // namespace npapi
289 } // namespace webkit
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698