| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO : Support NP_ASFILEONLY mode | 5 // TODO : Support NP_ASFILEONLY mode |
| 6 // TODO : Support NP_SEEK mode | 6 // TODO : Support NP_SEEK mode |
| 7 // TODO : Support SEEKABLE=true in NewStream | 7 // TODO : Support SEEKABLE=true in NewStream |
| 8 | 8 |
| 9 #include "webkit/glue/plugins/plugin_stream.h" | 9 #include "webkit/glue/plugins/plugin_stream.h" |
| 10 | 10 |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" |
| 13 #include "webkit/glue/plugins/plugin_instance.h" | 13 #include "webkit/glue/plugins/plugin_instance.h" |
| 14 #include "webkit/glue/webkit_glue.h" | 14 #include "webkit/glue/webkit_glue.h" |
| 15 #include "googleurl/src/gurl.h" | 15 #include "googleurl/src/gurl.h" |
| 16 | 16 |
| 17 namespace NPAPI { | 17 namespace NPAPI { |
| 18 | 18 |
| 19 PluginStream::PluginStream( | 19 PluginStream::PluginStream( |
| 20 PluginInstance *instance, | 20 PluginInstance *instance, |
| 21 const char *url, | 21 const char *url, |
| 22 bool need_notify, | 22 bool need_notify, |
| 23 void *notify_data) | 23 void *notify_data) |
| 24 : instance_(instance), | 24 : instance_(instance), |
| 25 bytes_sent_(0), | |
| 26 notify_needed_(need_notify), | 25 notify_needed_(need_notify), |
| 27 notify_data_(notify_data), | 26 notify_data_(notify_data), |
| 28 close_on_write_data_(false), | 27 close_on_write_data_(false), |
| 29 opened_(false), | 28 opened_(false), |
| 30 requested_plugin_mode_(NP_NORMAL), | 29 requested_plugin_mode_(NP_NORMAL), |
| 31 temp_file_handle_(INVALID_HANDLE_VALUE) { | 30 temp_file_handle_(INVALID_HANDLE_VALUE), |
| 31 seekable_stream_(false), |
| 32 data_offset_(0) { |
| 32 memset(&stream_, 0, sizeof(stream_)); | 33 memset(&stream_, 0, sizeof(stream_)); |
| 33 stream_.url = _strdup(url); | 34 stream_.url = _strdup(url); |
| 34 temp_file_name_[0] = '\0'; | 35 temp_file_name_[0] = '\0'; |
| 35 } | 36 } |
| 36 | 37 |
| 37 PluginStream::~PluginStream() { | 38 PluginStream::~PluginStream() { |
| 38 // always cleanup our temporary files. | 39 // always cleanup our temporary files. |
| 39 CleanupTempFile(); | 40 CleanupTempFile(); |
| 40 | |
| 41 free(const_cast<char*>(stream_.url)); | 41 free(const_cast<char*>(stream_.url)); |
| 42 } | 42 } |
| 43 | 43 |
| 44 void PluginStream::UpdateUrl(const char* url) { | 44 void PluginStream::UpdateUrl(const char* url) { |
| 45 DCHECK(!opened_); | 45 DCHECK(!opened_); |
| 46 free(const_cast<char*>(stream_.url)); | 46 free(const_cast<char*>(stream_.url)); |
| 47 stream_.url = _strdup(url); | 47 stream_.url = _strdup(url); |
| 48 } | 48 } |
| 49 | 49 |
| 50 bool PluginStream::Open(const std::string &mime_type, | 50 bool PluginStream::Open(const std::string &mime_type, |
| 51 const std::string &headers, | 51 const std::string &headers, |
| 52 uint32 length, | 52 uint32 length, |
| 53 uint32 last_modified) { | 53 uint32 last_modified) { |
| 54 headers_ = headers; | 54 headers_ = headers; |
| 55 NPP id = instance_->npp(); | 55 NPP id = instance_->npp(); |
| 56 stream_.end = length; | 56 stream_.end = length; |
| 57 stream_.lastmodified = last_modified; | 57 stream_.lastmodified = last_modified; |
| 58 stream_.pdata = 0; | 58 stream_.pdata = 0; |
| 59 stream_.ndata = id->ndata; | 59 stream_.ndata = id->ndata; |
| 60 stream_.notifyData = notify_data_; | 60 stream_.notifyData = notify_data_; |
| 61 if (!headers_.empty()) | 61 |
| 62 bool seekable_stream = false; |
| 63 if (!headers_.empty()) { |
| 62 stream_.headers = headers_.c_str(); | 64 stream_.headers = headers_.c_str(); |
| 65 if (headers_.find("Accept-Ranges: bytes") != std::string::npos) { |
| 66 seekable_stream = true; |
| 67 } |
| 68 } |
| 63 | 69 |
| 64 const char *char_mime_type = "application/x-unknown-content-type"; | 70 const char *char_mime_type = "application/x-unknown-content-type"; |
| 65 std::string temp_mime_type; | 71 std::string temp_mime_type; |
| 66 if (!mime_type.empty()) { | 72 if (!mime_type.empty()) { |
| 67 char_mime_type = mime_type.c_str(); | 73 char_mime_type = mime_type.c_str(); |
| 68 } else { | 74 } else { |
| 69 GURL gurl(stream_.url); | 75 GURL gurl(stream_.url); |
| 70 std::wstring path(UTF8ToWide(gurl.path())); | 76 std::wstring path(UTF8ToWide(gurl.path())); |
| 71 if (webkit_glue::GetMimeTypeFromFile(path, &temp_mime_type)) | 77 if (webkit_glue::GetMimeTypeFromFile(path, &temp_mime_type)) |
| 72 char_mime_type = temp_mime_type.c_str(); | 78 char_mime_type = temp_mime_type.c_str(); |
| 73 } | 79 } |
| 74 | 80 |
| 75 // Silverlight expects a valid mime type | 81 // Silverlight expects a valid mime type |
| 76 DCHECK(strlen(char_mime_type) != 0); | 82 DCHECK(strlen(char_mime_type) != 0); |
| 77 NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type, | 83 NPError err = instance_->NPP_NewStream((NPMIMEType)char_mime_type, |
| 78 &stream_, false, | 84 &stream_, seekable_stream, |
| 79 &requested_plugin_mode_); | 85 &requested_plugin_mode_); |
| 80 if (err != NPERR_NO_ERROR) | 86 if (err != NPERR_NO_ERROR) |
| 81 return false; | 87 return false; |
| 82 | 88 |
| 83 opened_ = true; | 89 opened_ = true; |
| 84 | 90 |
| 91 if (requested_plugin_mode_ == NP_SEEK) { |
| 92 seekable_stream_ = true; |
| 93 } |
| 94 |
| 85 // If the plugin has requested certain modes, then we need a copy | 95 // If the plugin has requested certain modes, then we need a copy |
| 86 // of this file on disk. Open it and save it as we go. | 96 // of this file on disk. Open it and save it as we go. |
| 87 if (requested_plugin_mode_ == NP_ASFILEONLY || | 97 if (requested_plugin_mode_ == NP_ASFILEONLY || |
| 88 requested_plugin_mode_ == NP_ASFILE || | 98 requested_plugin_mode_ == NP_ASFILE) { |
| 89 requested_plugin_mode_ == NP_SEEK) { | |
| 90 if (OpenTempFile() == false) | 99 if (OpenTempFile() == false) |
| 91 return false; | 100 return false; |
| 92 } | 101 } |
| 93 | 102 |
| 103 mime_type_ = char_mime_type; |
| 94 return true; | 104 return true; |
| 95 } | 105 } |
| 96 | 106 |
| 97 int PluginStream::Write(const char *buffer, const int length) { | 107 int PluginStream::Write(const char *buffer, const int length, |
| 108 int data_offset) { |
| 98 // There may be two streams to write to - the plugin and the file. | 109 // There may be two streams to write to - the plugin and the file. |
| 99 // It is unclear what to do if we cannot write to both. The rules of | 110 // It is unclear what to do if we cannot write to both. The rules of |
| 100 // this function are that the plugin must consume at least as many | 111 // this function are that the plugin must consume at least as many |
| 101 // bytes as returned by the WriteReady call. So, we will attempt to | 112 // bytes as returned by the WriteReady call. So, we will attempt to |
| 102 // write that many to both streams. If we can't write that many bytes | 113 // write that many to both streams. If we can't write that many bytes |
| 103 // to each stream, we'll return failure. | 114 // to each stream, we'll return failure. |
| 104 | 115 |
| 105 DCHECK(opened_); | 116 DCHECK(opened_); |
| 106 if (WriteToFile(buffer, length) && WriteToPlugin(buffer, length)) | 117 if (WriteToFile(buffer, length) && |
| 118 WriteToPlugin(buffer, length, data_offset)) |
| 107 return length; | 119 return length; |
| 108 | 120 |
| 109 return -1; | 121 return -1; |
| 110 } | 122 } |
| 111 | 123 |
| 112 bool PluginStream::WriteToFile(const char *buf, const int length) { | 124 bool PluginStream::WriteToFile(const char *buf, const int length) { |
| 113 // For ASFILEONLY, ASFILE, and SEEK modes, we need to write | 125 // For ASFILEONLY, ASFILE, and SEEK modes, we need to write |
| 114 // to the disk | 126 // to the disk |
| 115 if (temp_file_handle_ != INVALID_HANDLE_VALUE && | 127 if (temp_file_handle_ != INVALID_HANDLE_VALUE && |
| 116 (requested_plugin_mode_ == NP_SEEK || | 128 (requested_plugin_mode_ == NP_ASFILE || |
| 117 requested_plugin_mode_ == NP_ASFILE || | |
| 118 requested_plugin_mode_ == NP_ASFILEONLY) ) { | 129 requested_plugin_mode_ == NP_ASFILEONLY) ) { |
| 119 int totalBytesWritten = 0; | 130 int totalBytesWritten = 0; |
| 120 DWORD bytes; | 131 DWORD bytes; |
| 121 do { | 132 do { |
| 122 if (WriteFile(temp_file_handle_, buf, length, &bytes, 0) == FALSE) | 133 if (WriteFile(temp_file_handle_, buf, length, &bytes, 0) == FALSE) |
| 123 break; | 134 break; |
| 124 totalBytesWritten += bytes; | 135 totalBytesWritten += bytes; |
| 125 } while (bytes > 0 && totalBytesWritten < length); | 136 } while (bytes > 0 && totalBytesWritten < length); |
| 126 | 137 |
| 127 if (totalBytesWritten != length) | 138 if (totalBytesWritten != length) |
| 128 return false; | 139 return false; |
| 129 } | 140 } |
| 130 | 141 |
| 131 return true; | 142 return true; |
| 132 } | 143 } |
| 133 | 144 |
| 134 bool PluginStream::WriteToPlugin(const char *buf, const int length) { | 145 bool PluginStream::WriteToPlugin(const char *buf, const int length, |
| 146 const int data_offset) { |
| 135 // For NORMAL and ASFILE modes, we send the data to the plugin now | 147 // For NORMAL and ASFILE modes, we send the data to the plugin now |
| 136 if (requested_plugin_mode_ != NP_NORMAL && | 148 if (requested_plugin_mode_ != NP_NORMAL && |
| 137 requested_plugin_mode_ != NP_ASFILE) | 149 requested_plugin_mode_ != NP_ASFILE && |
| 150 requested_plugin_mode_ != NP_SEEK) |
| 138 return true; | 151 return true; |
| 139 | 152 |
| 140 int written = TryWriteToPlugin(buf, length); | 153 int written = TryWriteToPlugin(buf, length, data_offset); |
| 141 if (written == -1) | 154 if (written == -1) |
| 142 return false; | 155 return false; |
| 143 | 156 |
| 144 if (written < length) { | 157 if (written < length) { |
| 145 // Buffer the remaining data. | 158 // Buffer the remaining data. |
| 146 size_t remaining = length - written; | 159 size_t remaining = length - written; |
| 147 size_t previous_size = delivery_data_.size(); | 160 size_t previous_size = delivery_data_.size(); |
| 148 delivery_data_.resize(previous_size + remaining); | 161 delivery_data_.resize(previous_size + remaining); |
| 162 data_offset_ = data_offset; |
| 149 memcpy(&delivery_data_[previous_size], buf + written, remaining); | 163 memcpy(&delivery_data_[previous_size], buf + written, remaining); |
| 150 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( | 164 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( |
| 151 this, &PluginStream::OnDelayDelivery)); | 165 this, &PluginStream::OnDelayDelivery)); |
| 152 } | 166 } |
| 153 | 167 |
| 154 return true; | 168 return true; |
| 155 } | 169 } |
| 156 | 170 |
| 157 void PluginStream::OnDelayDelivery() { | 171 void PluginStream::OnDelayDelivery() { |
| 158 // It is possible that the plugin stream may have closed before the task | 172 // It is possible that the plugin stream may have closed before the task |
| 159 // was hit. | 173 // was hit. |
| 160 if (!opened_) { | 174 if (!opened_) { |
| 161 return; | 175 return; |
| 162 } | 176 } |
| 163 | 177 |
| 164 int size = static_cast<int>(delivery_data_.size()); | 178 int size = static_cast<int>(delivery_data_.size()); |
| 165 int written = TryWriteToPlugin(&delivery_data_.front(), size); | 179 int written = TryWriteToPlugin(&delivery_data_.front(), size, |
| 180 data_offset_); |
| 166 if (written > 0) { | 181 if (written > 0) { |
| 167 // Remove the data that we already wrote. | 182 // Remove the data that we already wrote. |
| 168 delivery_data_.erase(delivery_data_.begin(), | 183 delivery_data_.erase(delivery_data_.begin(), |
| 169 delivery_data_.begin() + written); | 184 delivery_data_.begin() + written); |
| 170 } | 185 } |
| 171 } | 186 } |
| 172 | 187 |
| 173 int PluginStream::TryWriteToPlugin(const char *buf, const int length) { | 188 int PluginStream::TryWriteToPlugin(const char *buf, const int length, |
| 189 const int data_offset) { |
| 174 bool result = true; | 190 bool result = true; |
| 175 int byte_offset = 0; | 191 int byte_offset = 0; |
| 176 | 192 |
| 193 if (data_offset > 0) |
| 194 data_offset_ = data_offset; |
| 195 |
| 177 while (byte_offset < length) { | 196 while (byte_offset < length) { |
| 178 int bytes_remaining = length - byte_offset; | 197 int bytes_remaining = length - byte_offset; |
| 179 int bytes_to_write = instance_->NPP_WriteReady(&stream_); | 198 int bytes_to_write = instance_->NPP_WriteReady(&stream_); |
| 180 if (bytes_to_write > bytes_remaining) | 199 if (bytes_to_write > bytes_remaining) |
| 181 bytes_to_write = bytes_remaining; | 200 bytes_to_write = bytes_remaining; |
| 182 | 201 |
| 183 if (bytes_to_write == 0) | 202 if (bytes_to_write == 0) |
| 184 return byte_offset; | 203 return byte_offset; |
| 185 | 204 |
| 186 int bytes_consumed = instance_->NPP_Write( | 205 int bytes_consumed = instance_->NPP_Write( |
| 187 &stream_, bytes_sent_, bytes_to_write, | 206 &stream_, data_offset_, bytes_to_write, |
| 188 const_cast<char*>(buf + byte_offset)); | 207 const_cast<char*>(buf + byte_offset)); |
| 189 if (bytes_consumed < 0) { | 208 if (bytes_consumed < 0) { |
| 190 // The plugin failed, which means that we need to close the stream. | 209 // The plugin failed, which means that we need to close the stream. |
| 191 Close(NPRES_NETWORK_ERR); | 210 Close(NPRES_NETWORK_ERR); |
| 192 return -1; | 211 return -1; |
| 193 } | 212 } |
| 194 if (bytes_consumed == 0) { | 213 if (bytes_consumed == 0) { |
| 195 // The plugin couldn't take all of the data now. | 214 // The plugin couldn't take all of the data now. |
| 196 return byte_offset; | 215 return byte_offset; |
| 197 } | 216 } |
| 198 | 217 |
| 199 // The plugin might report more that we gave it. | 218 // The plugin might report more that we gave it. |
| 200 bytes_consumed = std::min(bytes_consumed, bytes_to_write); | 219 bytes_consumed = std::min(bytes_consumed, bytes_to_write); |
| 201 | 220 |
| 202 bytes_sent_ += bytes_consumed; | 221 data_offset_ += bytes_consumed; |
| 203 byte_offset += bytes_consumed; | 222 byte_offset += bytes_consumed; |
| 204 } | 223 } |
| 205 | 224 |
| 206 if (close_on_write_data_) | 225 if (close_on_write_data_) |
| 207 Close(NPRES_DONE); | 226 Close(NPRES_DONE); |
| 208 | 227 |
| 209 return length; | 228 return length; |
| 210 } | 229 } |
| 211 | 230 |
| 212 void PluginStream::WriteAsFile() { | 231 void PluginStream::WriteAsFile() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 298 | 317 |
| 299 void PluginStream::Notify(NPReason reason) { | 318 void PluginStream::Notify(NPReason reason) { |
| 300 if (notify_needed_) { | 319 if (notify_needed_) { |
| 301 instance_->NPP_URLNotify(stream_.url, reason, notify_data_); | 320 instance_->NPP_URLNotify(stream_.url, reason, notify_data_); |
| 302 notify_needed_ = false; | 321 notify_needed_ = false; |
| 303 } | 322 } |
| 304 } | 323 } |
| 305 | 324 |
| 306 } // namespace NPAPI | 325 } // namespace NPAPI |
| 307 | 326 |
| OLD | NEW |