<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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.

#include "DocumentHost.h"

#include "errorcodes.h"
#include "logging.h"

#include "BrowserCookie.h"
#include "BrowserFactory.h"
#include "CookieManager.h"
#include "messages.h"
#include "RegistryUtilities.h"
#include "Script.h"
#include "StringUtilities.h"

namespace webdriver {

DocumentHost::DocumentHost(HWND hwnd, HWND executor_handle) {
  LOG(TRACE) << "Entering DocumentHost::DocumentHost";

  // NOTE: COM should be initialized on this thread, so we
  // could use CoCreateGuid() and StringFromGUID2() instead.
  UUID guid;
  RPC_WSTR guid_string = NULL;
  RPC_STATUS status = ::UuidCreate(&guid);
  if (status != RPC_S_OK) {
    // If we encounter an error, not bloody much we can do about it.
    // Just log it and continue.
    LOG(WARN) << "UuidCreate returned a status other then RPC_S_OK: " << status;
  }
  status = ::UuidToString(&guid, &guid_string);
  if (status != RPC_S_OK) {
    // If we encounter an error, not bloody much we can do about it.
    // Just log it and continue.
    LOG(WARN) << "UuidToString returned a status other then RPC_S_OK: " << status;
  }

  // RPC_WSTR is currently typedef'd in RpcDce.h (pulled in by rpc.h)
  // as unsigned short*. It needs to be typedef'd as wchar_t* 
  wchar_t* cast_guid_string = reinterpret_cast<wchar_t*>(guid_string);
  this->browser_id_ = StringUtilities::ToString(cast_guid_string);

  ::RpcStringFree(&guid_string);

  this->window_handle_ = hwnd;
  this->executor_handle_ = executor_handle;
  this->script_executor_handle_ = NULL;
  this->is_closing_ = false;
  this->wait_required_ = false;
  this->focused_frame_window_ = NULL;
  this->cookie_manager_ = new CookieManager();
  this->cookie_manager_->Initialize(this->window_handle_);
}

DocumentHost::~DocumentHost(void) {
  delete this->cookie_manager_;
}

std::string DocumentHost::GetCurrentUrl() {
  LOG(TRACE) << "Entering DocumentHost::GetCurrentUrl";

  CComPtr<IHTMLDocument2> doc;
  this->GetDocument(&doc);
  if (!doc) {
    LOG(WARN) << "Unable to get document object, DocumentHost::GetDocument returned NULL. "
              << "Attempting to get URL from IWebBrowser2 object";
    return this->GetBrowserUrl();
  }

  CComBSTR url;
  HRESULT hr = doc->get_URL(&url);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Unable to get current URL, call to IHTMLDocument2::get_URL failed";
    return "";
  }

  std::wstring converted_url(url, ::SysStringLen(url));
  std::string current_url = StringUtilities::ToString(converted_url);
  return current_url;
}

std::string DocumentHost::GetPageSource() {
  LOG(TRACE) << "Entering DocumentHost::GetPageSource";

  CComPtr<IHTMLDocument2> doc;
  this->GetDocument(&doc);
  if (!doc) {
    LOG(WARN) << "Unable to get document object, DocumentHost::GetDocument did not return a valid IHTMLDocument2 pointer";
    return "";
  }

  CComPtr<IHTMLDocument3> doc3;
  HRESULT hr = doc->QueryInterface<IHTMLDocument3>(&doc3);
  if (FAILED(hr) || !doc3) {
    LOG(WARN) << "Unable to get document object, QueryInterface to IHTMLDocument3 failed";
    return "";
  }

  CComPtr<IHTMLElement> document_element;
  hr = doc3->get_documentElement(&document_element);
  if (FAILED(hr) || !document_element) {
    LOGHR(WARN, hr) << "Unable to get document element from page, call to IHTMLDocument3::get_documentElement failed";
    return "";
  }

  CComBSTR html;
  hr = document_element->get_outerHTML(&html);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Have document element but cannot read source, call to IHTMLElement::get_outerHTML failed";
    return "";
  }

  std::wstring converted_html = html;
  std::string page_source = StringUtilities::ToString(converted_html);
  return page_source;
}

void DocumentHost::Restore(void) {
  if (this->IsFullScreen()) {
    this->SetFullScreen(false);
  }
  HWND window_handle = this->GetTopLevelWindowHandle();
  if (::IsZoomed(window_handle) || ::IsIconic(window_handle)) {
    ::ShowWindow(window_handle, SW_RESTORE);
  }
}

int DocumentHost::SetFocusedFrameByElement(IHTMLElement* frame_element) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByElement";

  HRESULT hr = S_OK;
  if (!frame_element) {
    this->focused_frame_window_ = NULL;
    return WD_SUCCESS;
  }

  CComPtr<IHTMLFrameBase2> frame_base;
  frame_element->QueryInterface<IHTMLFrameBase2>(&frame_base);
  if (!frame_base) {
    LOG(WARN) << "IHTMLElement is not a FRAME or IFRAME element";
    return ENOSUCHFRAME;
  }

  CComPtr<IHTMLWindow2> interim_result;
  hr = frame_base->get_contentWindow(&interim_result);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Cannot get contentWindow from IHTMLFrameBase2, call to IHTMLFrameBase2::get_contentWindow failed";
    return ENOSUCHFRAME;
  }

  this->focused_frame_window_ = interim_result;
  return WD_SUCCESS;
}

int DocumentHost::SetFocusedFrameByName(const std::string& frame_name) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByName";
  CComVariant frame_identifier =  StringUtilities::ToWString(frame_name).c_str();
  return this->SetFocusedFrameByIdentifier(frame_identifier);
}

int DocumentHost::SetFocusedFrameByIndex(const int frame_index) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByIndex";
  CComVariant frame_identifier;
  frame_identifier.vt = VT_I4;
  frame_identifier.lVal = frame_index;
  return this->SetFocusedFrameByIdentifier(frame_identifier);
}

void DocumentHost::SetFocusedFrameToParent() {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameToParent";
  // Three possible outcomes.
  // Outcome 1: Already at top-level browsing context. No-op.
  if (this->focused_frame_window_ != NULL) {
    CComPtr<IHTMLWindow2> parent_window;
    HRESULT hr = this->focused_frame_window_->get_parent(&parent_window);
    if (FAILED(hr)) {
      LOGHR(WARN, hr) << "IHTMLWindow2::get_parent call failed.";<commit_msg>Treat object tag with embedded document as frame<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The SFC licenses this file
// to you 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.

#include "DocumentHost.h"

#include "errorcodes.h"
#include "logging.h"

#include "BrowserCookie.h"
#include "BrowserFactory.h"
#include "CookieManager.h"
#include "messages.h"
#include "RegistryUtilities.h"
#include "Script.h"
#include "StringUtilities.h"

namespace webdriver {

DocumentHost::DocumentHost(HWND hwnd, HWND executor_handle) {
  LOG(TRACE) << "Entering DocumentHost::DocumentHost";

  // NOTE: COM should be initialized on this thread, so we
  // could use CoCreateGuid() and StringFromGUID2() instead.
  UUID guid;
  RPC_WSTR guid_string = NULL;
  RPC_STATUS status = ::UuidCreate(&guid);
  if (status != RPC_S_OK) {
    // If we encounter an error, not bloody much we can do about it.
    // Just log it and continue.
    LOG(WARN) << "UuidCreate returned a status other then RPC_S_OK: " << status;
  }
  status = ::UuidToString(&guid, &guid_string);
  if (status != RPC_S_OK) {
    // If we encounter an error, not bloody much we can do about it.
    // Just log it and continue.
    LOG(WARN) << "UuidToString returned a status other then RPC_S_OK: " << status;
  }

  // RPC_WSTR is currently typedef'd in RpcDce.h (pulled in by rpc.h)
  // as unsigned short*. It needs to be typedef'd as wchar_t* 
  wchar_t* cast_guid_string = reinterpret_cast<wchar_t*>(guid_string);
  this->browser_id_ = StringUtilities::ToString(cast_guid_string);

  ::RpcStringFree(&guid_string);

  this->window_handle_ = hwnd;
  this->executor_handle_ = executor_handle;
  this->script_executor_handle_ = NULL;
  this->is_closing_ = false;
  this->wait_required_ = false;
  this->focused_frame_window_ = NULL;
  this->cookie_manager_ = new CookieManager();
  this->cookie_manager_->Initialize(this->window_handle_);
}

DocumentHost::~DocumentHost(void) {
  delete this->cookie_manager_;
}

std::string DocumentHost::GetCurrentUrl() {
  LOG(TRACE) << "Entering DocumentHost::GetCurrentUrl";

  CComPtr<IHTMLDocument2> doc;
  this->GetDocument(&doc);
  if (!doc) {
    LOG(WARN) << "Unable to get document object, DocumentHost::GetDocument returned NULL. "
              << "Attempting to get URL from IWebBrowser2 object";
    return this->GetBrowserUrl();
  }

  CComBSTR url;
  HRESULT hr = doc->get_URL(&url);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Unable to get current URL, call to IHTMLDocument2::get_URL failed";
    return "";
  }

  std::wstring converted_url(url, ::SysStringLen(url));
  std::string current_url = StringUtilities::ToString(converted_url);
  return current_url;
}

std::string DocumentHost::GetPageSource() {
  LOG(TRACE) << "Entering DocumentHost::GetPageSource";

  CComPtr<IHTMLDocument2> doc;
  this->GetDocument(&doc);
  if (!doc) {
    LOG(WARN) << "Unable to get document object, DocumentHost::GetDocument did not return a valid IHTMLDocument2 pointer";
    return "";
  }

  CComPtr<IHTMLDocument3> doc3;
  HRESULT hr = doc->QueryInterface<IHTMLDocument3>(&doc3);
  if (FAILED(hr) || !doc3) {
    LOG(WARN) << "Unable to get document object, QueryInterface to IHTMLDocument3 failed";
    return "";
  }

  CComPtr<IHTMLElement> document_element;
  hr = doc3->get_documentElement(&document_element);
  if (FAILED(hr) || !document_element) {
    LOGHR(WARN, hr) << "Unable to get document element from page, call to IHTMLDocument3::get_documentElement failed";
    return "";
  }

  CComBSTR html;
  hr = document_element->get_outerHTML(&html);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Have document element but cannot read source, call to IHTMLElement::get_outerHTML failed";
    return "";
  }

  std::wstring converted_html = html;
  std::string page_source = StringUtilities::ToString(converted_html);
  return page_source;
}

void DocumentHost::Restore(void) {
  if (this->IsFullScreen()) {
    this->SetFullScreen(false);
  }
  HWND window_handle = this->GetTopLevelWindowHandle();
  if (::IsZoomed(window_handle) || ::IsIconic(window_handle)) {
    ::ShowWindow(window_handle, SW_RESTORE);
  }
}

int DocumentHost::SetFocusedFrameByElement(IHTMLElement* frame_element) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByElement";

  HRESULT hr = S_OK;
  if (!frame_element) {
    this->focused_frame_window_ = NULL;
    return WD_SUCCESS;
  }

  CComPtr<IHTMLWindow2> interim_result;
  CComPtr<IHTMLObjectElement4> object_element;
  hr = frame_element->QueryInterface<IHTMLObjectElement4>(&object_element);
  if (SUCCEEDED(hr) && object_element) {
	  CComPtr<IDispatch> object_disp;
	  object_element->get_contentDocument(&object_disp);
	  if (!object_disp) {
		  LOG(WARN) << "Cannot get IDispatch interface from IHTMLObjectElement4 element";
		  return ENOSUCHFRAME;
	  }

	  CComPtr<IHTMLDocument2> object_doc;
	  object_disp->QueryInterface<IHTMLDocument2>(&object_doc);
	  if (!object_doc) {
		  LOG(WARN) << "Cannot get IHTMLDocument2 document from IDispatch reference";
		  return ENOSUCHFRAME;
	  }

	  hr = object_doc->get_parentWindow(&interim_result);
	  if (FAILED(hr)) {
		  LOGHR(WARN, hr) << "Cannot get parentWindow from IHTMLDocument2, call to IHTMLDocument2::get_parentWindow failed";
		  return ENOSUCHFRAME;
	  }
  } else {
	  CComPtr<IHTMLFrameBase2> frame_base;
	  frame_element->QueryInterface<IHTMLFrameBase2>(&frame_base);
	  if (!frame_base) {
		  LOG(WARN) << "IHTMLElement is not a FRAME or IFRAME element";
		  return ENOSUCHFRAME;
	  }

	  hr = frame_base->get_contentWindow(&interim_result);
	  if (FAILED(hr)) {
		  LOGHR(WARN, hr) << "Cannot get contentWindow from IHTMLFrameBase2, call to IHTMLFrameBase2::get_contentWindow failed";
		  return ENOSUCHFRAME;
	  }
  }

  this->focused_frame_window_ = interim_result;
  return WD_SUCCESS;
}

int DocumentHost::SetFocusedFrameByName(const std::string& frame_name) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByName";
  CComVariant frame_identifier =  StringUtilities::ToWString(frame_name).c_str();
  return this->SetFocusedFrameByIdentifier(frame_identifier);
}

int DocumentHost::SetFocusedFrameByIndex(const int frame_index) {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameByIndex";
  CComVariant frame_identifier;
  frame_identifier.vt = VT_I4;
  frame_identifier.lVal = frame_index;
  return this->SetFocusedFrameByIdentifier(frame_identifier);
}

void DocumentHost::SetFocusedFrameToParent() {
  LOG(TRACE) << "Entering DocumentHost::SetFocusedFrameToParent";
  // Three possible outcomes.
  // Outcome 1: Already at top-level browsing context. No-op.
  if (this->focused_frame_window_ != NULL) {
    CComPtr<IHTMLWindow2> parent_window;
    HRESULT hr = this->focused_frame_window_->get_parent(&parent_window);
    if (FAILED(hr)) {
      LOGHR(WARN, hr) << "IHTMLWindow2::get_parent call failed.";
{'fraction_non_alphanumeric': 0.11610301400877317, 'fraction_numerical': 0.0043865855384179996, 'mean_word_length': 4.752950752950753, 'pattern_counts': {'":': 0, '<': 118, '<?xml version=': 0, '>': 94, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '749843', 'n_tokens_mistral': 4550, 'n_tokens_neox': 4469, 'n_words': 1162}