1
// Copyright 2005, Google Inc.
3
// Redistribution and use in source and binary forms, with or without
4
// modification, are permitted provided that the following conditions are met:
6
// 1. Redistributions of source code must retain the above copyright notice,
7
// this list of conditions and the following disclaimer.
8
// 2. Redistributions in binary form must reproduce the above copyright notice,
9
// this list of conditions and the following disclaimer in the documentation
10
// and/or other materials provided with the distribution.
11
// 3. Neither the name of Google Inc. nor the names of its contributors may be
12
// used to endorse or promote products derived from this software without
13
// specific prior written permission.
15
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
16
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
18
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#include "gears/localserver/resource_store_module.h"
28
#if BROWSER_IE || BROWSER_IEMOBILE
32
#include "gears/base/common/js_dom_element.h"
33
#include "gears/base/common/mime_detect.h"
34
#include "gears/base/common/url_utils.h"
35
#include "gears/blob/blob.h"
36
#include "gears/blob/buffer_blob.h"
37
#include "gears/blob/file_blob.h"
38
#include "gears/localserver/common/http_constants.h"
39
#include "gears/localserver/file_submitter.h"
42
//-----------------------------------------------------------------------------
43
// GearsResourceStoreMessageHwnd
44
//-----------------------------------------------------------------------------
45
#if BROWSER_IE || BROWSER_IEMOBILE
46
class GearsResourceStoreMessageHwnd
47
: public CWindowImpl<GearsResourceStoreMessageHwnd> {
49
static const int kCaptureTaskMessageBase = WM_USER;
51
WM_CAPTURE_TASK_COMPLETE = CaptureTask::CAPTURE_TASK_COMPLETE
52
+ kCaptureTaskMessageBase;
54
WM_CAPTURE_URL_SUCCEEDED = CaptureTask::CAPTURE_URL_SUCCEEDED
55
+ kCaptureTaskMessageBase;
57
WM_CAPTURE_URL_FAILED = CaptureTask::CAPTURE_URL_FAILED
58
+ kCaptureTaskMessageBase;
60
BEGIN_MSG_MAP(GearsResourceStoreMessageHwnd)
61
MESSAGE_HANDLER(WM_CAPTURE_TASK_COMPLETE, OnCaptureTaskComplete)
62
MESSAGE_HANDLER(WM_CAPTURE_URL_SUCCEEDED, OnCaptureUrlComplete)
63
MESSAGE_HANDLER(WM_CAPTURE_URL_FAILED, OnCaptureUrlComplete)
66
GearsResourceStoreMessageHwnd(GearsResourceStore *resource_store)
67
: resource_store_(resource_store) {}
70
// Make sure we have an HWND
72
if (!Create(kMessageOnlyWindowParent, // parent
75
kMessageOnlyWindowStyle)) { // style
81
LRESULT OnCaptureTaskComplete(UINT uMsg,
85
CaptureTask* task = reinterpret_cast<CaptureTask*>(lParam);
86
if (task && (task == resource_store_->capture_task_.get())) {
87
resource_store_->OnCaptureTaskComplete();
93
LRESULT OnCaptureUrlComplete(UINT uMsg,
97
CaptureTask* task = reinterpret_cast<CaptureTask*>(lParam);
98
if (task && (task == resource_store_->capture_task_.get())) {
100
bool success = (uMsg == WM_CAPTURE_URL_SUCCEEDED);
101
resource_store_->OnCaptureUrlComplete(index, success);
107
void OnFinalMessage(HWND hwnd) {
112
GearsResourceStore *resource_store_;
113
DISALLOW_EVIL_CONSTRUCTORS(GearsResourceStoreMessageHwnd);
118
//------------------------------------------------------------------------------
119
// GearsResourceStore
120
//------------------------------------------------------------------------------
121
DECLARE_DISPATCHER(GearsResourceStore);
125
void Dispatcher<GearsResourceStore>::Init() {
126
RegisterProperty("name", &GearsResourceStore::GetName, NULL);
127
RegisterProperty("requiredCookie", &GearsResourceStore::GetRequiredCookie,
129
RegisterProperty("enabled", &GearsResourceStore::GetEnabled,
130
&GearsResourceStore::SetEnabled);
132
RegisterMethod("capture", &GearsResourceStore::Capture);
133
RegisterMethod("abortCapture", &GearsResourceStore::AbortCapture);
134
RegisterMethod("isCaptured", &GearsResourceStore::IsCaptured);
135
RegisterMethod("remove", &GearsResourceStore::Remove);
136
RegisterMethod("rename", &GearsResourceStore::Rename);
137
RegisterMethod("copy", &GearsResourceStore::Copy);
138
RegisterMethod("getHeader", &GearsResourceStore::GetHeader);
139
RegisterMethod("getAllHeaders", &GearsResourceStore::GetAllHeaders);
140
RegisterMethod("getAsBlob", &GearsResourceStore::GetAsBlob);
141
RegisterMethod("captureBlob", &GearsResourceStore::CaptureBlob);
142
RegisterMethod("captureFile", &GearsResourceStore::CaptureFile);
143
RegisterMethod("getCapturedFileName",
144
&GearsResourceStore::GetCapturedFileName);
145
RegisterMethod("createFileSubmitter",
146
&GearsResourceStore::CreateFileSubmitter);
149
const std::string GearsResourceStore::kModuleName("GearsResourceStore");
151
GearsResourceStore::GearsResourceStore()
152
: ModuleImplBaseClass(kModuleName),
153
#if BROWSER_IE || BROWSER_IEMOBILE
154
message_hwnd_(new GearsResourceStoreMessageHwnd(this)),
156
next_capture_id_(0), page_is_unloaded_(false) {}
158
GearsResourceStore::~GearsResourceStore() {
160
#if BROWSER_IE || BROWSER_IEMOBILE
161
if (message_hwnd_->IsWindow()) {
162
message_hwnd_->DestroyWindow();
164
delete message_hwnd_;
169
//------------------------------------------------------------------------------
171
//------------------------------------------------------------------------------
172
void GearsResourceStore::GetName(JsCallContext *context) {
173
std::string16 name(store_.GetName());
174
context->SetReturnValue(JSPARAM_STRING16, &name);
177
//------------------------------------------------------------------------------
179
//------------------------------------------------------------------------------
180
void GearsResourceStore::GetRequiredCookie(JsCallContext *context) {
181
std::string16 cookie(store_.GetRequiredCookie());
182
context->SetReturnValue(JSPARAM_STRING16, &cookie);
185
//------------------------------------------------------------------------------
187
//------------------------------------------------------------------------------
188
void GearsResourceStore::GetEnabled(JsCallContext *context) {
189
bool enabled = store_.IsEnabled();
190
context->SetReturnValue(JSPARAM_BOOL, &enabled);
193
//------------------------------------------------------------------------------
195
//------------------------------------------------------------------------------
196
void GearsResourceStore::SetEnabled(JsCallContext *context) {
198
JsArgument argv[] = {
199
{ JSPARAM_REQUIRED, JSPARAM_BOOL, &enabled },
201
context->GetArguments(ARRAYSIZE(argv), argv);
202
if (context->is_exception_set())
205
if (!store_.SetEnabled(enabled)) {
206
context->SetException(STRING16(L"Failed to set the enabled property."));
211
//------------------------------------------------------------------------------
213
//------------------------------------------------------------------------------
214
void GearsResourceStore::Capture(JsCallContext *context) {
216
scoped_ptr<JsArray> url_array;
217
JsRootedCallback *callback = NULL;
219
JsArgument argv[] = {
220
{ JSPARAM_REQUIRED, JSPARAM_UNKNOWN, NULL },
221
{ JSPARAM_OPTIONAL, JSPARAM_FUNCTION, &callback },
224
// TODO(aa): Consider coercing anything except array to string. This would
225
// make it consistent with XMLHttpRequest and window.setTimeout.
226
int url_arg_type = context->GetArgumentType(0);
227
if (url_arg_type == JSPARAM_ARRAY) {
228
argv[0].type = JSPARAM_ARRAY;
229
argv[0].value_ptr = as_out_parameter(url_array);
230
} else if (url_arg_type == JSPARAM_STRING16) {
231
argv[0].type = JSPARAM_STRING16;
232
argv[0].value_ptr = &url;
234
context->SetException(
235
STRING16(L"First parameter must be an array or string."));
239
context->GetArguments(ARRAYSIZE(argv), argv);
240
scoped_ptr<JsRootedCallback> scoped_callback(callback);
241
if (context->is_exception_set())
244
int capture_id = ++next_capture_id_;
245
LOG(("ResourceStore::capture - id = %d\n", capture_id));
247
scoped_ptr<CaptureRequest> request(new CaptureRequest);
248
request->id = capture_id;
249
request->callback.swap(scoped_callback); // transfer ownership
251
if (url_arg_type == JSPARAM_ARRAY) {
252
// 'urls' was an array of strings
254
if (!url_array->GetLength(&array_length)) {
255
context->SetException(GET_INTERNAL_ERROR_MESSAGE());
259
for (int i = 0; i < array_length; ++i) {
260
if (!url_array->GetElementAsString(i, &url)) {
261
context->SetException(STRING16(L"Invalid parameter."));
265
if (!ResolveAndAppendUrl(url.c_str(), request.get())) {
266
context->SetException(exception_message_.c_str());
271
// 'urls' was a string
272
if (!ResolveAndAppendUrl(url.c_str(), request.get())) {
273
context->SetException(exception_message_.c_str());
278
pending_requests_.push_back(request.release());
280
if (!StartCaptureTaskIfNeeded(false)) {
281
context->SetException(exception_message_);
285
context->SetReturnValue(JSPARAM_INT, &capture_id);
288
//------------------------------------------------------------------------------
290
//------------------------------------------------------------------------------
291
void GearsResourceStore::AbortCapture(JsCallContext *context) {
293
JsArgument argv[] = {
294
{ JSPARAM_REQUIRED, JSPARAM_INT, &capture_id },
296
context->GetArguments(ARRAYSIZE(argv), argv);
297
if (context->is_exception_set())
300
if (current_request_.get() && (current_request_->id == capture_id)) {
301
// The caller is aborting the task that we're running
302
assert(capture_task_.get());
303
if (capture_task_.get()) {
304
capture_task_->Abort();
309
// Search for capture_id in our pending queue
310
std::deque<CaptureRequest*>::iterator iter;
311
for (iter = pending_requests_.begin();
312
iter < pending_requests_.end();
314
if ((*iter)->id == capture_id) {
315
// Remove it from the queue and fire completion events
316
CaptureRequest *request = (*iter);
317
pending_requests_.erase(iter);
318
FireFailedEvents(request);
321
// Note: the deque.erase() call is safe here since we return and
322
// do not continue the iteration
327
//------------------------------------------------------------------------------
329
//------------------------------------------------------------------------------
330
void GearsResourceStore::IsCaptured(JsCallContext *context) {
332
JsArgument argv[] = {
333
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
335
context->GetArguments(ARRAYSIZE(argv), argv);
336
if (context->is_exception_set())
339
std::string16 full_url;
340
if (!ResolveUrl(url, &full_url)) {
341
context->SetException(exception_message_.c_str());
344
bool is_captured = store_.IsCaptured(full_url.c_str());
345
context->SetReturnValue(JSPARAM_BOOL, &is_captured);
348
//------------------------------------------------------------------------------
350
//------------------------------------------------------------------------------
351
void GearsResourceStore::Remove(JsCallContext *context) {
353
JsArgument argv[] = {
354
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
356
context->GetArguments(ARRAYSIZE(argv), argv);
357
if (context->is_exception_set())
360
std::string16 full_url;
361
if (!ResolveUrl(url, &full_url)) {
362
context->SetException(exception_message_.c_str());
366
if (!store_.Delete(full_url.c_str())) {
367
context->SetException(STRING16(L"Failure removing url."));
372
//------------------------------------------------------------------------------
374
//------------------------------------------------------------------------------
375
void GearsResourceStore::Rename(JsCallContext *context) {
376
std::string16 src_url;
377
std::string16 dest_url;
378
JsArgument argv[] = {
379
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &src_url },
380
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &dest_url },
382
context->GetArguments(ARRAYSIZE(argv), argv);
383
if (context->is_exception_set())
386
std::string16 full_src_url;
387
if (!ResolveUrl(src_url, &full_src_url)) {
388
context->SetException(exception_message_.c_str());
392
std::string16 full_dest_url;
393
if (!ResolveUrl(dest_url, &full_dest_url)) {
394
context->SetException(exception_message_.c_str());
398
if (!store_.Rename(full_src_url.c_str(), full_dest_url.c_str())) {
399
context->SetException(STRING16(L"Failure renaming url."));
404
//------------------------------------------------------------------------------
406
//------------------------------------------------------------------------------
407
void GearsResourceStore::Copy(JsCallContext *context) {
408
std::string16 src_url;
409
std::string16 dest_url;
410
JsArgument argv[] = {
411
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &src_url },
412
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &dest_url },
414
context->GetArguments(ARRAYSIZE(argv), argv);
415
if (context->is_exception_set())
418
std::string16 full_src_url;
419
if (!ResolveUrl(src_url, &full_src_url)) {
420
context->SetException(exception_message_.c_str());
424
std::string16 full_dest_url;
425
if (!ResolveUrl(dest_url, &full_dest_url)) {
426
context->SetException(exception_message_.c_str());
430
if (!store_.Copy(full_src_url.c_str(), full_dest_url.c_str())) {
431
context->SetException(STRING16(L"Failure copying url."));
436
//------------------------------------------------------------------------------
438
//------------------------------------------------------------------------------
439
void GearsResourceStore::GetAsBlob(JsCallContext *context) {
441
JsArgument argv[] = {
442
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url }
444
context->GetArguments(ARRAYSIZE(argv), argv);
445
if (context->is_exception_set()) {
448
std::string16 full_url;
449
if (!ResolveUrl(url.c_str(), &full_url)) {
450
context->SetException(exception_message_.c_str());
454
ResourceStore::Item item;
455
scoped_refptr<BlobInterface> blob;
456
#ifdef USE_FILE_STORE
457
// TODO(michaeln): This is not quite right, but its better than allocating
458
// huge amounts of memory. Provided the store/item are not removed so long
459
// as the returned blob is around, this is fine and good. Otherwise some
461
// * By the time we are creating the file blob, the file may have been
462
// deleted if some other thread/process had removed this entry or store
463
// between the calls to GetItemInfo() and new FileBlob()
464
// * Removing the entry while the GearsBlob instance is out there is
465
// problematic, the system will want to delete the underlying file and
466
// depending on the OS may or may not succeed at that. Subsequent use
467
// of the outstanding GearsBlob may or may not work depending.
468
if (!store_.GetItemInfo(full_url.c_str(), &item)) {
469
context->SetException(STRING16(L"Failed to get blob."));
472
if (!item.payload.cached_filepath.empty())
473
blob.reset(new FileBlob(item.payload.cached_filepath));
475
blob.reset(new EmptyBlob());
477
if (!store_.GetItem(full_url.c_str(), &item)) {
478
context->SetException(STRING16(L"Failed to get blob."));
481
assert(item.payload.data.get());
482
blob.reset(new BufferBlob(item.payload.data.get());
485
scoped_refptr<GearsBlob> blob_object;
486
if (!CreateModule<GearsBlob>(module_environment_.get(),
487
context, &blob_object)) {
488
context->SetException(GET_INTERNAL_ERROR_MESSAGE());
491
blob_object->Reset(blob.get());
492
context->SetReturnValue(JSPARAM_MODULE, blob_object.get());
495
//------------------------------------------------------------------------------
497
// TODO(michaeln): provide a means of setting the Content-Disposition header
498
// to indicate the blob should be treated as an attachment.
499
//------------------------------------------------------------------------------
500
void GearsResourceStore::CaptureBlob(JsCallContext *context) {
501
ModuleImplBaseClass *other_module = NULL;
502
std::string16 url, content_type;
503
JsArgument argv[] = {
504
{ JSPARAM_REQUIRED, JSPARAM_MODULE, &other_module },
505
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
506
{ JSPARAM_OPTIONAL, JSPARAM_STRING16, &content_type }
508
context->GetArguments(ARRAYSIZE(argv), argv);
509
if (context->is_exception_set()) {
512
std::string16 full_url;
513
if (!ResolveUrl(url.c_str(), &full_url)) {
514
context->SetException(exception_message_.c_str());
517
if (!content_type.empty() && !IsValidHttpHeaderValue(content_type)) {
518
context->SetException(STRING16(L"Invalid content type."));
522
if (GearsBlob::kModuleName != other_module->get_module_name()) {
523
context->SetException(STRING16(L"First argument must be a Blob."));
526
scoped_refptr<BlobInterface> blob;
527
static_cast<GearsBlob*>(other_module)->GetContents(&blob);
530
ResourceStore::Item item;
531
if (!ResourceStore::BlobToItem(blob.get(), full_url.c_str(),
532
content_type.c_str(),
534
!store_.PutItem(&item)) {
535
context->SetException(STRING16(L"The blob could not be captured."));
540
//------------------------------------------------------------------------------
542
//------------------------------------------------------------------------------
543
void GearsResourceStore::CaptureFile(JsCallContext *context) {
545
// TODO(nigeltao): implement on NPAPI. To do this, I need to figure out how
546
// a FileInputElement is represented.
547
context->SetException(STRING16(L"captureFile is not implemented."));
550
context->SetException(
551
STRING16(L"captureFile is not supported in workers."));
555
JsDomElement dom_element;
557
JsArgument argv[] = {
558
{ JSPARAM_REQUIRED, JSPARAM_DOM_ELEMENT, &dom_element },
559
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url }
561
context->GetArguments(ARRAYSIZE(argv), argv);
562
if (context->is_exception_set()) {
565
std::string16 full_url;
566
if (!ResolveUrl(url.c_str(), &full_url)) {
567
context->SetException(STRING16(L"Failed to resolve url."));
571
std::string16 file_name;
572
if (!dom_element.GetFileInputElementValue(&file_name)) {
573
context->SetException(
574
STRING16(L"Failed to get the file name from the file input element."));
577
if (file_name.empty()) {
578
context->SetException(STRING16(L"File path is empty."));
581
if (!File::Exists(file_name.c_str())) {
582
context->SetException(STRING16(L"File does not exist."));
585
std::string16 file_base_name;
586
if (!File::GetBaseName(file_name, &file_base_name)) {
587
context->SetException(STRING16(L"Could not extract the file's base name."));
590
std::string16 mime_type = DetectMimeTypeOfFile(file_name);
591
scoped_refptr<BlobInterface> blob(new FileBlob(file_name));
593
ResourceStore::Item item;
594
if (!ResourceStore::BlobToItem(blob.get(), full_url.c_str(),
595
mime_type.c_str(), file_base_name.c_str(),
597
!store_.PutItem(&item)) {
598
context->SetException(STRING16(L"The file could not be captured."));
604
//------------------------------------------------------------------------------
605
// GetCapturedFileName
606
//------------------------------------------------------------------------------
607
void GearsResourceStore::GetCapturedFileName(JsCallContext *context) {
609
JsArgument argv[] = {
610
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
612
context->GetArguments(ARRAYSIZE(argv), argv);
613
if (context->is_exception_set())
616
std::string16 full_url;
617
if (!ResolveUrl(url, &full_url)) {
618
context->SetException(exception_message_.c_str());
622
std::string16 file_name;
623
if (!store_.GetCapturedFileName(full_url.c_str(), &file_name)) {
624
context->SetException(STRING16(L"GetCapturedFileName failed."));
628
context->SetReturnValue(JSPARAM_STRING16, &file_name);
631
//------------------------------------------------------------------------------
633
//------------------------------------------------------------------------------
634
void GearsResourceStore::GetHeader(JsCallContext *context) {
637
JsArgument argv[] = {
638
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
639
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &name },
641
context->GetArguments(ARRAYSIZE(argv), argv);
642
if (context->is_exception_set())
645
std::string16 full_url;
646
if (!ResolveUrl(url, &full_url)) {
647
context->SetException(exception_message_.c_str());
652
store_.GetHeader(full_url.c_str(), name.c_str(), &value);
653
context->SetReturnValue(JSPARAM_STRING16, &value);
656
//------------------------------------------------------------------------------
658
//------------------------------------------------------------------------------
659
void GearsResourceStore::GetAllHeaders(JsCallContext *context) {
661
JsArgument argv[] = {
662
{ JSPARAM_REQUIRED, JSPARAM_STRING16, &url },
664
context->GetArguments(ARRAYSIZE(argv), argv);
665
if (context->is_exception_set())
668
std::string16 full_url;
669
if (!ResolveUrl(url, &full_url)) {
670
context->SetException(exception_message_.c_str());
674
std::string16 all_headers;
675
if (!store_.GetAllHeaders(full_url.c_str(), &all_headers)) {
676
context->SetException(STRING16(L"GetAllHeaders failed."));
680
context->SetReturnValue(JSPARAM_STRING16, &all_headers);
683
//------------------------------------------------------------------------------
684
// CreateFileSubmitter
685
//------------------------------------------------------------------------------
686
void GearsResourceStore::CreateFileSubmitter(JsCallContext *context) {
688
context->SetException(STRING16(L"createFileSubmitter is not implemented."));
691
// TODO(nigeltao): implement on NPAPI.
692
context->SetException(STRING16(L"createFileSubmitter is not implemented."));
696
context->SetException(
697
STRING16(L"createFileSubmitter cannot be called in a worker."));
701
scoped_refptr<GearsFileSubmitter> submitter;
702
if (!CreateModule<GearsFileSubmitter>(module_environment_.get(),
703
context, &submitter)) {
706
if (!submitter->store_.Clone(&store_)) {
707
context->SetException(STRING16(L"Error initializing base class."));
711
context->SetReturnValue(JSPARAM_MODULE, submitter.get());
715
// End Javascript API
717
//------------------------------------------------------------------------------
719
//------------------------------------------------------------------------------
720
void GearsResourceStore::HandleEvent(JsEventType event_type) {
721
assert(event_type == JSEVENT_UNLOAD);
723
page_is_unloaded_ = true;
728
//------------------------------------------------------------------------------
730
//------------------------------------------------------------------------------
731
void GearsResourceStore::AbortAllRequests() {
732
if (capture_task_.get()) {
733
#if BROWSER_IE || BROWSER_IEMOBILE
734
capture_task_->SetListenerWindow(NULL, 0);
736
capture_task_->SetListener(NULL);
738
// No need to fire failed events since the current page is being unloaded
739
// or the resource store deleted for some other reason.
740
need_to_fire_failed_events_ = false;
741
capture_task_->Abort();
742
capture_task_.release()->DeleteWhenDone();
745
if (current_request_.get()) {
746
current_request_->callback.reset(NULL);
749
for (std::deque<CaptureRequest*>::iterator iter = pending_requests_.begin();
750
iter != pending_requests_.end(); ++iter) {
753
pending_requests_.clear();
756
//------------------------------------------------------------------------------
757
// StartCaptureTaskIfNeeded
758
//------------------------------------------------------------------------------
759
bool GearsResourceStore::StartCaptureTaskIfNeeded(bool fire_events_on_failure) {
760
if (page_is_unloaded_) {
761
// We silently fail for this particular error condition to prevent callers
762
// from detecting errors and making noises after the page has been unloaded
766
// Create an event monitor to alert us when the page unloads.
767
if (unload_monitor_ == NULL) {
768
unload_monitor_.reset(new JsEventMonitor(GetJsRunner(), JSEVENT_UNLOAD,
772
if (capture_task_.get()) {
773
assert(current_request_.get());
777
if (pending_requests_.empty()) {
781
assert(!current_request_.get());
782
current_request_.reset(pending_requests_.front());
783
pending_requests_.pop_front();
785
capture_task_.reset(new CaptureTask(EnvPageBrowsingContext()));
786
if (!capture_task_->Init(&store_, current_request_.get())) {
787
scoped_ptr<CaptureRequest> failed_request(current_request_.release());
788
capture_task_.reset(NULL);
789
if (fire_events_on_failure) {
790
FireFailedEvents(failed_request.get());
792
exception_message_ = STRING16(L"Failed to initialize capture task.");
796
#if BROWSER_IE || BROWSER_IEMOBILE
797
message_hwnd_->Initialize();
798
capture_task_->SetListenerWindow(
799
message_hwnd_->m_hWnd,
800
GearsResourceStoreMessageHwnd::kCaptureTaskMessageBase);
802
capture_task_->SetListener(this);
804
need_to_fire_failed_events_ = true;
805
if (!capture_task_->Start()) {
806
scoped_ptr<CaptureRequest> failed_request(current_request_.release());
807
capture_task_.reset(NULL);
808
if (fire_events_on_failure) {
809
FireFailedEvents(failed_request.get());
811
exception_message_ = STRING16(L"Failed to start capture task.");
818
//------------------------------------------------------------------------------
819
// HandleAsyncTaskEvent
820
//------------------------------------------------------------------------------
821
#if BROWSER_IE || BROWSER_IEMOBILE
822
// On IE, AsyncTask uses a GearsResourceStoreMessageHwnd instead.
824
void GearsResourceStore::HandleAsyncTaskEvent(int code, int param,
826
if (source && (source == capture_task_.get())) {
827
if (code == CaptureTask::CAPTURE_TASK_COMPLETE) {
828
OnCaptureTaskComplete();
830
// param = the index of the url that has been processed
831
bool success = (code == CaptureTask::CAPTURE_URL_SUCCEEDED);
832
OnCaptureUrlComplete(param, success);
838
//------------------------------------------------------------------------------
839
// OnCaptureUrlComplete
840
//------------------------------------------------------------------------------
841
void GearsResourceStore::OnCaptureUrlComplete(int index, bool success) {
842
if (current_request_.get()) {
843
need_to_fire_failed_events_ = false;
844
InvokeCompletionCallback(current_request_.get(),
845
current_request_->urls[index],
846
current_request_->id,
851
//------------------------------------------------------------------------------
852
// OnCaptureTaskComplete
853
//------------------------------------------------------------------------------
854
void GearsResourceStore::OnCaptureTaskComplete() {
855
#if BROWSER_IE || BROWSER_IEMOBILE
856
capture_task_->SetListenerWindow(NULL, 0);
858
capture_task_->SetListener(NULL);
860
capture_task_.release()->DeleteWhenDone();
861
if (need_to_fire_failed_events_) {
862
assert(current_request_.get());
863
FireFailedEvents(current_request_.get());
865
current_request_.reset(NULL);
866
StartCaptureTaskIfNeeded(true);
869
//------------------------------------------------------------------------------
871
//------------------------------------------------------------------------------
872
void GearsResourceStore::FireFailedEvents(CaptureRequest *request) {
874
for (size_t i = 0; i < request->urls.size(); ++i) {
875
InvokeCompletionCallback(request,
882
//------------------------------------------------------------------------------
883
// InvokeCompletionCallback
884
//------------------------------------------------------------------------------
885
void GearsResourceStore::InvokeCompletionCallback(
886
CaptureRequest *request,
887
const std::string16 &capture_url,
890
// If completion callback was not set, return immediately
891
if (!request->callback.get()) { return; }
894
JsParamToSend argv[argc] = {
895
{ JSPARAM_STRING16, &capture_url },
896
{ JSPARAM_BOOL, &succeeded },
897
{ JSPARAM_INT, &capture_id }
899
GetJsRunner()->InvokeCallback(
900
request->callback.get(), NULL, argc, argv, NULL);
903
//------------------------------------------------------------------------------
904
// ResolveAndAppendUrl
905
//------------------------------------------------------------------------------
906
bool GearsResourceStore::ResolveAndAppendUrl(const std::string16 &url,
907
CaptureRequest *request) {
908
std::string16 full_url;
909
if (!ResolveUrl(url.c_str(), &full_url)) {
912
request->urls.push_back(url);
913
request->full_urls.push_back(full_url);
917
//------------------------------------------------------------------------------
918
// This helper does several things:
919
// - resolve relative urls based on the page location, the 'url' may also
920
// be an absolute url to start with, if so this step does not modify it
921
// - normalizes the resulting absolute url, ie. removes path navigation
922
// - removes the fragment part of the url, ie. truncates at the '#' character
923
// - ensures the the resulting url is from the same-origin
924
//------------------------------------------------------------------------------
925
bool GearsResourceStore::ResolveUrl(const std::string16 &url,
926
std::string16 *resolved_url) {
927
if (!ResolveAndNormalize(EnvPageLocationUrl().c_str(), url.c_str(),
929
exception_message_ = STRING16(L"Failed to resolve url.");
932
if (!EnvPageSecurityOrigin().IsSameOriginAsUrl(resolved_url->c_str())) {
933
exception_message_ = STRING16(L"Url is not from the same origin");