OLD | NEW |
1 // Copyright 2009, Google Inc. | 1 // Copyright 2009, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 15 matching lines...) Expand all Loading... |
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | 29 |
30 #include "chrome_frame/npapi_url_request.h" | 30 #include "chrome_frame/npapi_url_request.h" |
31 | 31 |
32 #include "base/string_util.h" | 32 #include "base/string_util.h" |
33 #include "chrome_frame/np_browser_functions.h" | 33 #include "chrome_frame/np_browser_functions.h" |
34 #include "net/base/net_errors.h" | 34 #include "net/base/net_errors.h" |
35 | 35 |
| 36 class NPAPIUrlRequest : public PluginUrlRequest { |
| 37 public: |
| 38 explicit NPAPIUrlRequest(NPP instance); |
| 39 ~NPAPIUrlRequest(); |
| 40 |
| 41 virtual bool Start(); |
| 42 virtual void Stop(); |
| 43 virtual bool Read(int bytes_to_read); |
| 44 |
| 45 // Called from NPAPI |
| 46 bool OnStreamCreated(const char* mime_type, NPStream* stream); |
| 47 NPError OnStreamDestroyed(NPReason reason); |
| 48 int OnWriteReady(); |
| 49 int OnWrite(void* buffer, int len); |
| 50 |
| 51 // Thread unsafe implementation of ref counting, since |
| 52 // this will be called on the plugin UI thread only. |
| 53 virtual unsigned long API_CALL AddRef(); |
| 54 virtual unsigned long API_CALL Release(); |
| 55 |
| 56 private: |
| 57 PluginUrlRequestDelegate* delegate_; |
| 58 unsigned long ref_count_; |
| 59 NPP instance_; |
| 60 NPStream* stream_; |
| 61 size_t pending_read_size_; |
| 62 URLRequestStatus status_; |
| 63 |
| 64 PlatformThreadId thread_; |
| 65 static int instance_count_; |
| 66 DISALLOW_COPY_AND_ASSIGN(NPAPIUrlRequest); |
| 67 }; |
| 68 |
36 int NPAPIUrlRequest::instance_count_ = 0; | 69 int NPAPIUrlRequest::instance_count_ = 0; |
37 | 70 |
38 NPAPIUrlRequest::NPAPIUrlRequest(NPP instance) | 71 NPAPIUrlRequest::NPAPIUrlRequest(NPP instance) |
39 : ref_count_(0), instance_(instance), stream_(NULL), | 72 : ref_count_(0), instance_(instance), stream_(NULL), |
40 pending_read_size_(0), | 73 pending_read_size_(0), |
41 status_(URLRequestStatus::FAILED, net::ERR_FAILED), | 74 status_(URLRequestStatus::FAILED, net::ERR_FAILED), |
42 thread_(PlatformThread::CurrentId()) { | 75 thread_(PlatformThread::CurrentId()) { |
43 DLOG(INFO) << "Created request. Count: " << ++instance_count_; | 76 DLOG(INFO) << "Created request. Count: " << ++instance_count_; |
44 } | 77 } |
45 | 78 |
46 NPAPIUrlRequest::~NPAPIUrlRequest() { | 79 NPAPIUrlRequest::~NPAPIUrlRequest() { |
47 DLOG(INFO) << "Deleted request. Count: " << --instance_count_; | 80 DLOG(INFO) << "Deleted request. Count: " << --instance_count_; |
48 } | 81 } |
49 | 82 |
50 // NPAPIUrlRequest member defines. | 83 // NPAPIUrlRequest member defines. |
51 bool NPAPIUrlRequest::Start() { | 84 bool NPAPIUrlRequest::Start() { |
52 NPError result = NPERR_GENERIC_ERROR; | 85 NPError result = NPERR_GENERIC_ERROR; |
53 DLOG(INFO) << "Starting URL request: " << url(); | 86 DLOG(INFO) << "Starting URL request: " << url(); |
54 if (LowerCaseEqualsASCII(method(), "get")) { | 87 if (LowerCaseEqualsASCII(method(), "get")) { |
55 // TODO(joshia): if we have extra headers for HTTP GET, then implement | 88 // TODO(joshia): if we have extra headers for HTTP GET, then implement |
56 // it using XHR | 89 // it using XHR |
57 result = npapi::GetURLNotify(instance_, url().c_str(), NULL, this); | 90 result = npapi::GetURLNotify(instance_, url().c_str(), NULL, this); |
58 } else if (LowerCaseEqualsASCII(method(), "post")) { | 91 } else if (LowerCaseEqualsASCII(method(), "post")) { |
59 result = npapi::PostURLNotify(instance_, url().c_str(), NULL, | 92 result = npapi::PostURLNotify(instance_, url().c_str(), NULL, |
60 extra_headers().length(), extra_headers().c_str(), false, this); | 93 extra_headers().length(), extra_headers().c_str(), false, this); |
61 } else { | 94 } else { |
62 NOTREACHED() << "PluginUrlRequest only supports 'GET'/'POST'"; | 95 NOTREACHED() << "PluginUrlRequest only supports 'GET'/'POST'"; |
63 } | 96 } |
64 | 97 |
65 if (NPERR_NO_ERROR == result) { | 98 if (NPERR_NO_ERROR != result) { |
66 request_handler()->AddRequest(this); | |
67 } else { | |
68 int os_error = net::ERR_FAILED; | 99 int os_error = net::ERR_FAILED; |
69 switch (result) { | 100 switch (result) { |
70 case NPERR_INVALID_URL: | 101 case NPERR_INVALID_URL: |
71 os_error = net::ERR_INVALID_URL; | 102 os_error = net::ERR_INVALID_URL; |
72 break; | 103 break; |
73 default: | 104 default: |
74 break; | 105 break; |
75 } | 106 } |
76 | 107 |
77 OnResponseEnd(URLRequestStatus(URLRequestStatus::FAILED, os_error)); | 108 delegate_->OnResponseEnd(id(), |
| 109 URLRequestStatus(URLRequestStatus::FAILED, os_error)); |
78 return false; | 110 return false; |
79 } | 111 } |
80 | 112 |
81 return true; | 113 return true; |
82 } | 114 } |
83 | 115 |
84 void NPAPIUrlRequest::Stop() { | 116 void NPAPIUrlRequest::Stop() { |
85 DLOG(INFO) << "Finished request: Url - " << url() << " result: " | 117 DLOG(INFO) << "Finished request: Url - " << url() << " result: " |
86 << static_cast<int>(status_.status()); | 118 << static_cast<int>(status_.status()); |
87 if (stream_) { | 119 if (stream_) { |
88 npapi::DestroyStream(instance_, stream_, NPRES_USER_BREAK); | 120 npapi::DestroyStream(instance_, stream_, NPRES_USER_BREAK); |
89 stream_ = NULL; | 121 stream_ = NULL; |
90 } | 122 } |
91 | |
92 request_handler()->RemoveRequest(this); | |
93 if (!status_.is_io_pending()) | |
94 OnResponseEnd(status_); | |
95 } | 123 } |
96 | 124 |
97 bool NPAPIUrlRequest::Read(int bytes_to_read) { | 125 bool NPAPIUrlRequest::Read(int bytes_to_read) { |
98 pending_read_size_ = bytes_to_read; | 126 pending_read_size_ = bytes_to_read; |
99 return true; | 127 return true; |
100 } | 128 } |
101 | 129 |
102 bool NPAPIUrlRequest::OnStreamCreated(const char* mime_type, NPStream* stream) { | 130 bool NPAPIUrlRequest::OnStreamCreated(const char* mime_type, NPStream* stream) { |
103 stream_ = stream; | 131 stream_ = stream; |
104 status_.set_status(URLRequestStatus::IO_PENDING); | 132 status_.set_status(URLRequestStatus::IO_PENDING); |
105 // TODO(iyengar) | 133 // TODO(iyengar) |
106 // Add support for passing persistent cookies and information about any URL | 134 // Add support for passing persistent cookies and information about any URL |
107 // redirects to Chrome. | 135 // redirects to Chrome. |
108 OnResponseStarted(mime_type, stream->headers, stream->end, | 136 delegate_->OnResponseStarted(id(), mime_type, stream->headers, stream->end, |
109 base::Time::FromTimeT(stream->lastmodified), std::string(), | 137 base::Time::FromTimeT(stream->lastmodified), std::string(), |
110 std::string(), 0); | 138 std::string(), 0); |
111 return true; | 139 return true; |
112 } | 140 } |
113 | 141 |
114 void NPAPIUrlRequest::OnStreamDestroyed(NPReason reason) { | 142 NPError NPAPIUrlRequest::OnStreamDestroyed(NPReason reason) { |
115 URLRequestStatus::Status status = URLRequestStatus::FAILED; | 143 URLRequestStatus::Status status = URLRequestStatus::FAILED; |
116 switch (reason) { | 144 switch (reason) { |
117 case NPRES_DONE: | 145 case NPRES_DONE: |
118 status_.set_status(URLRequestStatus::SUCCESS); | 146 status_.set_status(URLRequestStatus::SUCCESS); |
119 status_.set_os_error(0); | 147 status_.set_os_error(0); |
120 break; | 148 break; |
121 case NPRES_USER_BREAK: | 149 case NPRES_USER_BREAK: |
122 status_.set_status(URLRequestStatus::CANCELED); | 150 status_.set_status(URLRequestStatus::CANCELED); |
123 status_.set_os_error(net::ERR_ABORTED); | 151 status_.set_os_error(net::ERR_ABORTED); |
124 break; | 152 break; |
125 case NPRES_NETWORK_ERR: | 153 case NPRES_NETWORK_ERR: |
126 default: | 154 default: |
127 status_.set_status(URLRequestStatus::FAILED); | 155 status_.set_status(URLRequestStatus::FAILED); |
128 status_.set_os_error(net::ERR_CONNECTION_CLOSED); | 156 status_.set_os_error(net::ERR_CONNECTION_CLOSED); |
129 break; | 157 break; |
130 } | 158 } |
| 159 |
| 160 delegate_->OnResponseEnd(id(), status_); |
| 161 return NPERR_NO_ERROR; |
131 } | 162 } |
132 | 163 |
133 int NPAPIUrlRequest::OnWriteReady() { | 164 int NPAPIUrlRequest::OnWriteReady() { |
134 return pending_read_size_; | 165 return pending_read_size_; |
135 } | 166 } |
136 | 167 |
137 int NPAPIUrlRequest::OnWrite(void* buffer, int len) { | 168 int NPAPIUrlRequest::OnWrite(void* buffer, int len) { |
138 pending_read_size_ = 0; | 169 pending_read_size_ = 0; |
139 OnReadComplete(buffer, len); | 170 delegate_->OnReadComplete(id(), buffer, len); |
140 return len; | 171 return len; |
141 } | 172 } |
142 | 173 |
143 STDMETHODIMP_(ULONG) NPAPIUrlRequest::AddRef() { | 174 STDMETHODIMP_(ULONG) NPAPIUrlRequest::AddRef() { |
144 DCHECK_EQ(PlatformThread::CurrentId(), thread_); | 175 DCHECK_EQ(PlatformThread::CurrentId(), thread_); |
145 ++ref_count_; | 176 ++ref_count_; |
146 return ref_count_; | 177 return ref_count_; |
147 } | 178 } |
148 | 179 |
149 STDMETHODIMP_(ULONG) NPAPIUrlRequest::Release() { | 180 STDMETHODIMP_(ULONG) NPAPIUrlRequest::Release() { |
150 DCHECK_EQ(PlatformThread::CurrentId(), thread_); | 181 DCHECK_EQ(PlatformThread::CurrentId(), thread_); |
151 unsigned long ret = --ref_count_; | 182 unsigned long ret = --ref_count_; |
152 if (!ret) | 183 if (!ret) |
153 delete this; | 184 delete this; |
154 | 185 |
155 return ret; | 186 return ret; |
156 } | 187 } |
157 | 188 |
| 189 NPAPIUrlRequestManager::NPAPIUrlRequestManager() : instance_(NULL) { |
| 190 } |
| 191 |
| 192 NPAPIUrlRequestManager::~NPAPIUrlRequestManager() { |
| 193 StopAll(); |
| 194 } |
| 195 |
| 196 // PluginUrlRequestManager implementation |
| 197 bool NPAPIUrlRequestManager::IsThreadSafe() { |
| 198 return false; |
| 199 } |
| 200 |
| 201 void NPAPIUrlRequestManager::StartRequest(int request_id, |
| 202 const IPC::AutomationURLRequest& request_info) { |
| 203 scoped_refptr<NPAPIUrlRequest> new_request(new NPAPIUrlRequest(instance_)); |
| 204 DCHECK(new_request); |
| 205 if (new_request->Initialize(this, request_id, request_info.url, |
| 206 request_info.method, request_info.referrer, |
| 207 request_info.extra_request_headers, request_info.upload_data.get(), |
| 208 enable_frame_busting_)) { |
| 209 // Add to map. |
| 210 DCHECK(NULL == request_map_[request_id].get()); |
| 211 request_map_[request_id] = new_request; |
| 212 if (new_request->Start()) { |
| 213 // Keep additional reference on request for NPSTREAM |
| 214 // This will be released in NPP_UrlNotify |
| 215 new_request->AddRef(); |
| 216 } |
| 217 } |
| 218 } |
| 219 |
| 220 void NPAPIUrlRequestManager::ReadRequest(int request_id, int bytes_to_read) { |
| 221 scoped_refptr<NPAPIUrlRequest> request = request_map_[request_id]; |
| 222 DCHECK(request.get()); |
| 223 if (request) |
| 224 request->Read(bytes_to_read); |
| 225 } |
| 226 |
| 227 void NPAPIUrlRequestManager::EndRequest(int request_id) { |
| 228 scoped_refptr<NPAPIUrlRequest> request = request_map_[request_id]; |
| 229 if (request) |
| 230 request->Stop(); |
| 231 } |
| 232 |
| 233 void NPAPIUrlRequestManager::StopAll() { |
| 234 for (RequestMap::iterator index = request_map_.begin(); |
| 235 index != request_map_.end(); |
| 236 ++index) { |
| 237 scoped_refptr<NPAPIUrlRequest> request = (*index).second; |
| 238 request->Stop(); |
| 239 } |
| 240 } |
| 241 |
| 242 // PluginRequestDelegate implementation. |
| 243 // Callbacks from NPAPIUrlRequest. Simply forward to the delegate. |
| 244 void NPAPIUrlRequestManager::OnResponseStarted(int request_id, |
| 245 const char* mime_type, const char* headers, int size, |
| 246 base::Time last_modified, const std::string& peristent_cookies, |
| 247 const std::string& redirect_url, int redirect_status) { |
| 248 delegate_->OnResponseStarted(request_id, mime_type, headers, size, |
| 249 last_modified, peristent_cookies, redirect_url, redirect_status); |
| 250 } |
| 251 |
| 252 void NPAPIUrlRequestManager::OnReadComplete(int request_id, const void* buffer, |
| 253 int len) { |
| 254 delegate_->OnReadComplete(request_id, buffer, len); |
| 255 } |
| 256 |
| 257 void NPAPIUrlRequestManager::OnResponseEnd(int request_id, |
| 258 const URLRequestStatus& status) { |
| 259 // Delete from map. |
| 260 RequestMap::iterator it = request_map_.find(request_id); |
| 261 DCHECK(request_map_.end() != it); |
| 262 scoped_refptr<NPAPIUrlRequest> request = (*it).second; |
| 263 request_map_.erase(it); |
| 264 |
| 265 // Inform delegate unless canceled. |
| 266 if (status.status() != URLRequestStatus::CANCELED) |
| 267 delegate_->OnResponseEnd(request_id, status); |
| 268 } |
| 269 |
| 270 // Notifications from browser. Find the NPAPIUrlRequest and forward to it. |
| 271 bool NPAPIUrlRequestManager::NewStream(NPMIMEType type, NPStream* stream, |
| 272 NPBool seekable, uint16* stream_type) { |
| 273 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData); |
| 274 DCHECK(request_map_.find(request->id()) != request_map_.end()); |
| 275 // We need to return the requested stream mode if we are returning a success |
| 276 // code. If we don't do this it causes Opera to blow up. |
| 277 *stream_type = NP_NORMAL; |
| 278 return request->OnStreamCreated(type, stream); |
| 279 } |
| 280 |
| 281 int32 NPAPIUrlRequestManager::WriteReady(NPStream* stream) { |
| 282 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData); |
| 283 DCHECK(request_map_.find(request->id()) != request_map_.end()); |
| 284 return request->OnWriteReady(); |
| 285 } |
| 286 |
| 287 int32 NPAPIUrlRequestManager::Write(NPStream* stream, int32 offset, |
| 288 int32 len, void* buffer) { |
| 289 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData); |
| 290 DCHECK(request_map_.find(request->id()) != request_map_.end()); |
| 291 return request->OnWrite(buffer, len); |
| 292 } |
| 293 |
| 294 NPError NPAPIUrlRequestManager::DestroyStream(NPStream* stream, |
| 295 NPReason reason) { |
| 296 NPAPIUrlRequest* request = RequestFromNotifyData(stream->notifyData); |
| 297 DCHECK(request_map_.find(request->id()) != request_map_.end()); |
| 298 return request->OnStreamDestroyed(reason); |
| 299 } |
| 300 |
| 301 void NPAPIUrlRequestManager::UrlNotify(const char* url, NPReason reason, |
| 302 void* notify_data) { |
| 303 NPAPIUrlRequest* request = RequestFromNotifyData(notify_data); |
| 304 if (request) { |
| 305 request->Stop(); |
| 306 request->Release(); |
| 307 } |
| 308 } |
OLD | NEW |