blob: d11689babf83d0dcaf31070a70b66ac617e2c684 [file] [log] [blame]
// Copyright 2011 Software Freedom Conservancy
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef WEBDRIVER_IE_SUBMITELEMENTCOMMANDHANDLER_H_
#define WEBDRIVER_IE_SUBMITELEMENTCOMMANDHANDLER_H_
#define SUBMIT_EVENT_NAME L"SubmitEvent"
#include "../Browser.h"
#include "../IECommandHandler.h"
#include "../IECommandExecutor.h"
#include "../Generated/atoms.h"
namespace webdriver {
class SubmitElementCommandHandler : public IECommandHandler {
public:
SubmitElementCommandHandler(void) {
}
virtual ~SubmitElementCommandHandler(void) {
}
protected:
void ExecuteInternal(const IECommandExecutor& executor,
const LocatorMap& locator_parameters,
const ParametersMap& command_parameters,
Response* response) {
LocatorMap::const_iterator id_parameter_iterator = locator_parameters.find("id");
if (id_parameter_iterator == locator_parameters.end()) {
response->SetErrorResponse(400, "Missing parameter in URL: id");
return;
} else {
std::string element_id = id_parameter_iterator->second;
BrowserHandle browser_wrapper;
int status_code = executor.GetCurrentBrowser(&browser_wrapper);
if (status_code != SUCCESS) {
response->SetErrorResponse(status_code, "Unable to get browser");
return;
}
ElementHandle element_wrapper;
status_code = this->GetElement(executor, element_id, &element_wrapper);
if (status_code == SUCCESS) {
// Use native events if we can. If not, use the automation atom.
bool handled_with_native_events = false;
CComQIPtr<IHTMLInputElement> input(element_wrapper->element());
if (input) {
CComBSTR type_name;
input->get_type(&type_name);
std::wstring type(type_name);
if (_wcsicmp(L"submit", type.c_str()) == 0 ||
_wcsicmp(L"image", type.c_str()) == 0) {
element_wrapper->Click(executor.input_manager()->scroll_behavior());
handled_with_native_events = true;
}
}
if (!handled_with_native_events) {
std::string submit_error = "";
if (executor.allow_asynchronous_javascript()) {
status_code = element_wrapper->ExecuteAsyncAtom(
SUBMIT_EVENT_NAME,
&SubmitElementCommandHandler::SubmitFormThreadProc,
&submit_error);
} else {
CComPtr<IHTMLDocument2> doc;
browser_wrapper->GetDocument(&doc);
CComVariant element_variant(element_wrapper->element());
status_code = ExecuteSubmitAtom(doc, element_variant);
}
if (status_code != SUCCESS) {
response->SetErrorResponse(status_code,
"Error submitting when not using native events. " + submit_error);
return;
}
}
browser_wrapper->set_wait_required(true);
response->SetSuccessResponse(Json::Value::null);
return;
} else {
response->SetErrorResponse(status_code, "Element is no longer valid");
return;
}
}
}
private:
void SubmitElementCommandHandler::FindParentForm(IHTMLElement *element,
IHTMLFormElement **form_element) {
CComQIPtr<IHTMLElement> current(element);
while (current) {
CComQIPtr<IHTMLFormElement> form(current);
if (form) {
*form_element = form.Detach();
return;
}
CComPtr<IHTMLElement> temp;
current->get_parentElement(&temp);
current = temp;
}
}
static int ExecuteSubmitAtom(IHTMLDocument2* doc, VARIANT element_variant) {
// The atom is just the definition of an anonymous
// function: "function() {...}"; Wrap it in another function so we can
// invoke it with our arguments without polluting the current namespace.
std::wstring script_source = L"(function() { return (";
script_source += atoms::asString(atoms::SUBMIT);
script_source += L")})();";
Script script_wrapper(doc, script_source, 1);
script_wrapper.AddArgument(element_variant);
int status_code = script_wrapper.Execute();
// Require a short sleep here to let the browser update the DOM.
::Sleep(100);
return status_code;
}
static unsigned int WINAPI SubmitFormThreadProc(LPVOID param) {
BOOL bRet;
MSG msg;
LOG(DEBUG) << "Initializing message pump on new thread";
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
LOG(DEBUG) << "Initializing COM on new thread";
HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
LOG(DEBUG) << "Unmarshaling document from stream";
CComPtr<IHTMLDocument2> doc;
LPSTREAM message_payload = reinterpret_cast<LPSTREAM>(param);
hr = ::CoGetInterfaceAndReleaseStream(message_payload,
IID_IHTMLDocument2,
reinterpret_cast<void**>(&doc));
LOG(DEBUG) << "Signaling parent thread that the worker thread is ready for messages";
HANDLE event_handle = ::OpenEvent(EVENT_MODIFY_STATE, FALSE, SUBMIT_EVENT_NAME);
if (event_handle != NULL) {
::SetEvent(event_handle);
::CloseHandle(event_handle);
}
while ((bRet = ::GetMessage(&msg, NULL, 0, 0)) != 0) {
if (msg.message == WD_EXECUTE_ASYNC_SCRIPT) {
LOG(DEBUG) << "Received execution message. Unmarshaling element from stream.";
int status_code = SUCCESS;
CComPtr<IDispatch> dispatch;
LPSTREAM message_payload = reinterpret_cast<LPSTREAM>(param);
hr = ::CoGetInterfaceAndReleaseStream(message_payload, IID_IDispatch, reinterpret_cast<void**>(&dispatch));
LOG(DEBUG) << "Element unmarshaled from stream, executing JavaScript on worker thread";
if (SUCCEEDED(hr) && dispatch != NULL) {
CComVariant element(dispatch);
status_code = ExecuteSubmitAtom(doc, element);
// The atom is just the definition of an anonymous
// function: "function() {...}"; Wrap it in another function so we can
// invoke it with our arguments without polluting the current namespace.
//std::wstring script_source = L"(function() { return (";
//script_source += atoms::asString(atoms::SUBMIT);
//script_source += L")})();";
//Script script_wrapper(doc, script_source, 1);
//script_wrapper.AddArgument(element);
//status_code = script_wrapper.Execute();
//// Require a short sleep here to let the browser update the DOM.
//::Sleep(100);
} else {
status_code = EUNEXPECTEDJSERROR;
}
::CoUninitialize();
return status_code;
}
}
return 0;
}
};
} // namespace webdriver
#endif // WEBDRIVER_IE_SUBMITELEMENTCOMMANDHANDLER_H_