<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/l10n_util.h"
#include "base/file_path.h"
#include "base/gfx/native_widget_types.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_unittest.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"

namespace {

// Given a page title, returns the expected window caption string.
std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
#if defined(OS_WIN) || defined(OS_LINUX)
  if (page_title.empty())
    return l10n_util::GetString(IDS_PRODUCT_NAME);

  return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, page_title);
#elif defined(OS_MACOSX)
  // On Mac, we don't want to suffix the page title with the application name.
  if (page_title.empty())
    return l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
  return page_title;
#endif
}

class BrowserTest : public UITest {
 protected:
#if defined(OS_WIN)
  HWND GetMainWindow() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    HWND window_handle;
    EXPECT_TRUE(window->GetHWND(&window_handle));
    return window_handle;
  }
#endif

  std::wstring GetWindowTitle() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    string16 title;
    EXPECT_TRUE(window->GetWindowTitle(&title));
    return UTF16ToWide(title);
  }
};

class VisibleBrowserTest : public UITest {
 protected:
  VisibleBrowserTest() : UITest() {
    show_window_ = true;
  }
};

// Launch the app on a page with no title, check that the app title was set
// correctly.
TEST_F(BrowserTest, NoTitle) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());
  EXPECT_EQ(WindowCaptionFromPageTitle(L"title1.html"), GetWindowTitle());
  EXPECT_EQ(L"title1.html", GetActiveTabTitle());
}

// Launch the app, navigate to a page with a title, check that the app title
// was set correctly.
TEST_F(BrowserTest, Title) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());

  const std::wstring test_title(L"Title Of Awesomeness");
  EXPECT_EQ(WindowCaptionFromPageTitle(test_title), GetWindowTitle());
  EXPECT_EQ(test_title, GetActiveTabTitle());
}

// Create 34 tabs and verify that a lot of processes have been created. The
// exact number of processes depends on the amount of memory. Previously we
// had a hard limit of 31 processes and this test is mainly directed at
// verifying that we don't crash when we pass this limit.
TEST_F(BrowserTest, ThirtyFourTabs) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");
  GURL url(net::FilePathToFileURL(test_file));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  // There is one initial tab.
  for (int ix = 0; ix != 33; ++ix) {
    EXPECT_TRUE(window->AppendTab(url));
  }
  int tab_count = 0;
  EXPECT_TRUE(window->GetTabCount(&tab_count));
  EXPECT_EQ(34, tab_count);
  // Do not test the rest in single process mode.
  if (in_process_renderer())
    return;
  // See browser\renderer_host\render_process_host.cc for the algorithm to
  // decide how many processes to create.
  int process_count = GetBrowserProcessCount();
  if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) {
    EXPECT_GE(process_count, 24);
  } else {
    EXPECT_LE(process_count, 23);
  }
}

#if defined(OS_WIN)
// The browser should quit quickly if it receives a WM_ENDSESSION message.
TEST_F(BrowserTest, WindowsSessionEnd) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  PlatformThread::Sleep(action_timeout_ms());

  // Simulate an end of session. Normally this happens when the user
  // shuts down the pc or logs off.
  HWND window_handle = GetMainWindow();
  ASSERT_TRUE(::PostMessageW(window_handle, WM_ENDSESSION, 0, 0));

  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_FALSE(IsBrowserRunning());

  // Make sure the UMA metrics say we didn't crash.
  scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
  bool exited_cleanly;
  ASSERT_TRUE(local_prefs.get());
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
                                      &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);

  // And that session end was successful.
  bool session_end_completed;
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
                                      &session_end_completed));
  ASSERT_TRUE(session_end_completed);

  // Make sure session restore says we didn't crash.
  scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
  ASSERT_TRUE(profile_prefs.get());
  ASSERT_TRUE(profile_prefs->GetBoolean(prefs::kSessionExitedCleanly,
                                        &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);
}
#endif

// This test is flakey, see bug 5668 for details.
TEST_F(BrowserTest, DISABLED_JavascriptAlertActivatesTab) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  int start_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&start_index));
  ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
  int javascript_tab_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&javascript_tab_index));
  scoped_refptr<TabProxy> javascript_tab = window->GetActiveTab();
  // Switch back to the starting tab, then send the second tab a javascript
  // alert, which should force it to become active.
  ASSERT_TRUE(window->ActivateTab(start_index));
  ASSERT_TRUE(
      javascript_tab->NavigateToURLAsync(GURL("javascript:alert('Alert!')")));
  ASSERT_TRUE(window->WaitForTabToBecomeActive(javascript_tab_index,
                                               action_max_timeout_ms()));
}

// Test that scripts can fork a new renderer process for a tab in a particular
// case (which matches following a link in Gmail).  The script must open a new
// tab, set its window.opener to null, and redirect it to a cross-site URL.
// (Bug 1115708)
// This test can only run if V8 is in use, and not KJS, because KJS will not
// set window.opener to null properly.
#ifdef CHROME_V8
TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to "fork" a new tab, just like Gmail.  (Open tab to a
  // blank page, set its opener to null, and redirect it cross-site.)
  std::wstring url_prefix(L"javascript:(function(){w=window.open();");
  GURL fork_url(url_prefix +
      L"w.opener=null;w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab has been created and that we have a new renderer
  // process for it.
  tab->NavigateToURLAsync(fork_url);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count + 1, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
}
#endif

#if !defined(OS_LINUX)
// TODO(port): This passes on linux locally, but fails on the try bot.
// Tests that non-Gmail-like script redirects (i.e., non-null window.opener) or
// a same-page-redirect) will not fork a new process.
TEST_F(BrowserTest, OtherRedirectsDontForkProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to almost fork a new tab, but not quite.  (Leave the
  // opener non-null.)  Should not fork a process.
  std::string url_prefix("javascript:(function(){w=window.open();");
  GURL dont_fork_url(url_prefix +
      "w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab but not new process has been created.
  tab->NavigateToURLAsync(dont_fork_url);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);

  // Same thing if the current tab tries to redirect itself.
  GURL dont_fork_url2(url_prefix +
      "document.location=\"http://localhost:1337\";})()");

  // Make sure that no new process has been created.
  tab->NavigateToURLAsync(dont_fork_url2);
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
}
#endif

#if defined(OS_WIN)
// TODO(estade): need to port GetActiveTabTitle().
TEST_F(VisibleBrowserTest, WindowOpenClose) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("window.close.html");

  NavigateToURL(net::FilePathToFileURL(test_file));

  int i;
  for (i = 0; i < 10; ++i) {
    PlatformThread::Sleep(action_max_timeout_ms() / 10);
    std::wstring title = GetActiveTabTitle();
    if (title == L"PASSED") {
      // Success, bail out.
      break;
    }
  }

  if (i == 10)
    FAIL() << "failed to get error page title";
}
#endif

}  // namespace
<commit_msg>Coverity underground warfare: check return code - Check return code consistently - CID 4171<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "app/l10n_util.h"
#include "base/file_path.h"
#include "base/gfx/native_widget_types.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "base/values.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/automation/browser_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/automation/window_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"
#include "net/url_request/url_request_unittest.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"

namespace {

// Given a page title, returns the expected window caption string.
std::wstring WindowCaptionFromPageTitle(std::wstring page_title) {
#if defined(OS_WIN) || defined(OS_LINUX)
  if (page_title.empty())
    return l10n_util::GetString(IDS_PRODUCT_NAME);

  return l10n_util::GetStringF(IDS_BROWSER_WINDOW_TITLE_FORMAT, page_title);
#elif defined(OS_MACOSX)
  // On Mac, we don't want to suffix the page title with the application name.
  if (page_title.empty())
    return l10n_util::GetString(IDS_BROWSER_WINDOW_MAC_TAB_UNTITLED);
  return page_title;
#endif
}

class BrowserTest : public UITest {
 protected:
#if defined(OS_WIN)
  HWND GetMainWindow() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    HWND window_handle;
    EXPECT_TRUE(window->GetHWND(&window_handle));
    return window_handle;
  }
#endif

  std::wstring GetWindowTitle() {
    scoped_refptr<BrowserProxy> browser(automation()->GetBrowserWindow(0));
    scoped_refptr<WindowProxy> window(browser->GetWindow());

    string16 title;
    EXPECT_TRUE(window->GetWindowTitle(&title));
    return UTF16ToWide(title);
  }
};

class VisibleBrowserTest : public UITest {
 protected:
  VisibleBrowserTest() : UITest() {
    show_window_ = true;
  }
};

// Launch the app on a page with no title, check that the app title was set
// correctly.
TEST_F(BrowserTest, NoTitle) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());
  EXPECT_EQ(WindowCaptionFromPageTitle(L"title1.html"), GetWindowTitle());
  EXPECT_EQ(L"title1.html", GetActiveTabTitle());
}

// Launch the app, navigate to a page with a title, check that the app title
// was set correctly.
TEST_F(BrowserTest, Title) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  // The browser lazily updates the title.
  PlatformThread::Sleep(sleep_timeout_ms());

  const std::wstring test_title(L"Title Of Awesomeness");
  EXPECT_EQ(WindowCaptionFromPageTitle(test_title), GetWindowTitle());
  EXPECT_EQ(test_title, GetActiveTabTitle());
}

// Create 34 tabs and verify that a lot of processes have been created. The
// exact number of processes depends on the amount of memory. Previously we
// had a hard limit of 31 processes and this test is mainly directed at
// verifying that we don't crash when we pass this limit.
TEST_F(BrowserTest, ThirtyFourTabs) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title2.html");
  GURL url(net::FilePathToFileURL(test_file));
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  // There is one initial tab.
  for (int ix = 0; ix != 33; ++ix) {
    EXPECT_TRUE(window->AppendTab(url));
  }
  int tab_count = 0;
  EXPECT_TRUE(window->GetTabCount(&tab_count));
  EXPECT_EQ(34, tab_count);
  // Do not test the rest in single process mode.
  if (in_process_renderer())
    return;
  // See browser\renderer_host\render_process_host.cc for the algorithm to
  // decide how many processes to create.
  int process_count = GetBrowserProcessCount();
  if (base::SysInfo::AmountOfPhysicalMemoryMB() >= 2048) {
    EXPECT_GE(process_count, 24);
  } else {
    EXPECT_LE(process_count, 23);
  }
}

#if defined(OS_WIN)
// The browser should quit quickly if it receives a WM_ENDSESSION message.
TEST_F(BrowserTest, WindowsSessionEnd) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("title1.html");

  NavigateToURL(net::FilePathToFileURL(test_file));
  PlatformThread::Sleep(action_timeout_ms());

  // Simulate an end of session. Normally this happens when the user
  // shuts down the pc or logs off.
  HWND window_handle = GetMainWindow();
  ASSERT_TRUE(::PostMessageW(window_handle, WM_ENDSESSION, 0, 0));

  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_FALSE(IsBrowserRunning());

  // Make sure the UMA metrics say we didn't crash.
  scoped_ptr<DictionaryValue> local_prefs(GetLocalState());
  bool exited_cleanly;
  ASSERT_TRUE(local_prefs.get());
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilityExitedCleanly,
                                      &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);

  // And that session end was successful.
  bool session_end_completed;
  ASSERT_TRUE(local_prefs->GetBoolean(prefs::kStabilitySessionEndCompleted,
                                      &session_end_completed));
  ASSERT_TRUE(session_end_completed);

  // Make sure session restore says we didn't crash.
  scoped_ptr<DictionaryValue> profile_prefs(GetDefaultProfilePreferences());
  ASSERT_TRUE(profile_prefs.get());
  ASSERT_TRUE(profile_prefs->GetBoolean(prefs::kSessionExitedCleanly,
                                        &exited_cleanly));
  ASSERT_TRUE(exited_cleanly);
}
#endif

// This test is flakey, see bug 5668 for details.
TEST_F(BrowserTest, DISABLED_JavascriptAlertActivatesTab) {
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  int start_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&start_index));
  ASSERT_TRUE(window->AppendTab(GURL("about:blank")));
  int javascript_tab_index;
  ASSERT_TRUE(window->GetActiveTabIndex(&javascript_tab_index));
  scoped_refptr<TabProxy> javascript_tab = window->GetActiveTab();
  // Switch back to the starting tab, then send the second tab a javascript
  // alert, which should force it to become active.
  ASSERT_TRUE(window->ActivateTab(start_index));
  ASSERT_TRUE(
      javascript_tab->NavigateToURLAsync(GURL("javascript:alert('Alert!')")));
  ASSERT_TRUE(window->WaitForTabToBecomeActive(javascript_tab_index,
                                               action_max_timeout_ms()));
}

// Test that scripts can fork a new renderer process for a tab in a particular
// case (which matches following a link in Gmail).  The script must open a new
// tab, set its window.opener to null, and redirect it to a cross-site URL.
// (Bug 1115708)
// This test can only run if V8 is in use, and not KJS, because KJS will not
// set window.opener to null properly.
#ifdef CHROME_V8
TEST_F(BrowserTest, NullOpenerRedirectForksProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to "fork" a new tab, just like Gmail.  (Open tab to a
  // blank page, set its opener to null, and redirect it cross-site.)
  std::wstring url_prefix(L"javascript:(function(){w=window.open();");
  GURL fork_url(url_prefix +
      L"w.opener=null;w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab has been created and that we have a new renderer
  // process for it.
  ASSERT_TRUE(tab->NavigateToURLAsync(fork_url));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count + 1, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);
}
#endif

#if !defined(OS_LINUX)
// TODO(port): This passes on linux locally, but fails on the try bot.
// Tests that non-Gmail-like script redirects (i.e., non-null window.opener) or
// a same-page-redirect) will not fork a new process.
TEST_F(BrowserTest, OtherRedirectsDontForkProcess) {
  // This test only works in multi-process mode
  if (in_process_renderer())
    return;

  const wchar_t kDocRoot[] = L"chrome/test/data";
  scoped_refptr<HTTPTestServer> server =
      HTTPTestServer::CreateServer(kDocRoot, NULL);
  ASSERT_TRUE(NULL != server.get());
  FilePath test_file(test_data_directory_);
  scoped_refptr<BrowserProxy> window(automation()->GetBrowserWindow(0));
  scoped_refptr<TabProxy> tab(window->GetActiveTab());

  // Start with a file:// url
  test_file = test_file.AppendASCII("title2.html");
  tab->NavigateToURL(net::FilePathToFileURL(test_file));
  int orig_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&orig_tab_count));
  int orig_process_count = GetBrowserProcessCount();
  ASSERT_GE(orig_process_count, 1);

  // Use JavaScript URL to almost fork a new tab, but not quite.  (Leave the
  // opener non-null.)  Should not fork a process.
  std::string url_prefix("javascript:(function(){w=window.open();");
  GURL dont_fork_url(url_prefix +
      "w.document.location=\"http://localhost:1337\";})()");

  // Make sure that a new tab but not new process has been created.
  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
  int new_tab_count = -1;
  ASSERT_TRUE(window->GetTabCount(&new_tab_count));
  ASSERT_EQ(orig_tab_count + 1, new_tab_count);

  // Same thing if the current tab tries to redirect itself.
  GURL dont_fork_url2(url_prefix +
      "document.location=\"http://localhost:1337\";})()");

  // Make sure that no new process has been created.
  ASSERT_TRUE(tab->NavigateToURLAsync(dont_fork_url2));
  PlatformThread::Sleep(action_timeout_ms());
  ASSERT_EQ(orig_process_count, GetBrowserProcessCount());
}
#endif

#if defined(OS_WIN)
// TODO(estade): need to port GetActiveTabTitle().
TEST_F(VisibleBrowserTest, WindowOpenClose) {
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("window.close.html");

  NavigateToURL(net::FilePathToFileURL(test_file));

  int i;
  for (i = 0; i < 10; ++i) {
    PlatformThread::Sleep(action_max_timeout_ms() / 10);
    std::wstring title = GetActiveTabTitle();
    if (title == L"PASSED") {
      // Success, bail out.
      break;
    }
  }

  if (i == 10)
    FAIL() << "failed to get error page title";
}
#endif

}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/plugin_service.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_plugin_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_updater.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/default_plugin.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/gpu_plugin.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#ifndef DISABLE_NACL
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#endif
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_MACOSX)
static void NotifyPluginsOfActivation() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    plugin->OnAppActivation();
  }
}
#endif

// static
bool PluginService::enable_chrome_plugins_ = true;

void LoadPluginsFromDiskHook() {
  DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI) &&
         !ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
         "Can't load plugins on the IO/UI threads since it's very slow.";
}

// static
void PluginService::InitGlobalInstance(Profile* profile) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  NPAPI::PluginList::Singleton()->SetPluginLoadHook(LoadPluginsFromDiskHook);

  // We first group the plugins and then figure out which groups to disable.
  PluginUpdater::GetPluginUpdater()->DisablePluginGroupsFromPrefs(profile);

  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDisableOutdatedPlugins)) {
    NPAPI::PluginList::Singleton()->DisableOutdatedPluginGroups();
  }

  // Have Chrome plugins write their data to the profile directory.
  GetInstance()->SetChromePluginDataDir(profile->GetPath());
}

// static
PluginService* PluginService::GetInstance() {
  return Singleton<PluginService>::get();
}

// static
void PluginService::EnableChromePlugins(bool enable) {
  enable_chrome_plugins_ = enable;
}

PluginService::PluginService()
    : main_message_loop_(MessageLoop::current()),
      resource_dispatcher_host_(NULL),
      ui_locale_(g_browser_process->GetApplicationLocale()) {
  RegisterPepperPlugins();

  // Have the NPAPI plugin list search for Chrome plugins as well.
  ChromePluginLib::RegisterPluginsWithNPAPI();

  // Load any specified on the command line as well.
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(path);

  chrome::RegisterInternalDefaultPlugin();

  // Register the internal Flash and PDF, if available.
  if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableInternalFlash) &&
      PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  }

#ifndef DISABLE_NACL
  if (command_line->HasSwitch(switches::kInternalNaCl)) {
    RegisterInternalNaClPlugin();
  }
#endif

  chrome::RegisterInternalGPUPlugin();

#if defined(OS_WIN)
  hkcu_key_.Create(
      HKEY_CURRENT_USER, kRegistryMozillaPlugins, KEY_NOTIFY);
  hklm_key_.Create(
      HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, KEY_NOTIFY);
  if (hkcu_key_.StartWatching()) {
    hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
    hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
  }

  if (hklm_key_.StartWatching()) {
    hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
    hklm_watcher_.StartWatching(hklm_event_.get(), this);
  }
#elif defined(OS_POSIX) && !defined(OS_MACOSX)
  // Also find plugins in a user-specific plugins dir,
  // e.g. ~/.config/chromium/Plugins.
  FilePath user_data_dir;
  if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(
        user_data_dir.Append("Plugins"));
  }
#endif

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
#if defined(OS_MACOSX)
  // We need to know when the browser comes forward so we can bring modal plugin
  // windows forward too.
  registrar_.Add(this, NotificationType::APP_ACTIVATED,
                 NotificationService::AllSources());
#endif
}

PluginService::~PluginService() {
#if defined(OS_WIN)
  // Release the events since they're owned by RegKey, not WaitableEvent.
  hkcu_watcher_.StopWatching();
  hklm_watcher_.StopWatching();
  hkcu_event_->Release();
  hklm_event_->Release();
#endif
}

void PluginService::LoadChromePlugins(
    ResourceDispatcherHost* resource_dispatcher_host) {
  if (!enable_chrome_plugins_)
    return;

  resource_dispatcher_host_ = resource_dispatcher_host;
  ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
}

void PluginService::SetChromePluginDataDir(const FilePath& data_dir) {
  chrome_plugin_data_dir_ = data_dir;
}

const FilePath& PluginService::GetChromePluginDataDir() {
  return chrome_plugin_data_dir_;
}

const std::string& PluginService::GetUILocale() {
  return ui_locale_;
}

PluginProcessHost* PluginService::FindPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (plugin_path.value().empty()) {
    NOTREACHED() << "should only be called if we have a plugin to load";
    return NULL;
  }

  for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    if (plugin->info().path == plugin_path)
      return plugin;
  }

  return NULL;
}

PluginProcessHost* PluginService::FindOrStartPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  PluginProcessHost *plugin_host = FindPluginProcess(plugin_path);
  if (plugin_host)
    return plugin_host;

  WebPluginInfo info;
  if (!NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
          plugin_path, &info)) {
    DCHECK(false);
    return NULL;
  }

  // This plugin isn't loaded by any plugin process, so create a new process.
  plugin_host = new PluginProcessHost();
  if (!plugin_host->Init(info, ui_locale_)) {
    DCHECK(false);  // Init is not expected to fail
    delete plugin_host;
    return NULL;
  }

  return plugin_host;
}

void PluginService::OpenChannelToPlugin(
    ResourceMessageFilter* renderer_msg_filter,
    const GURL& url,
    const std::string& mime_type,
    const std::string& locale,
    IPC::Message* reply_msg) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  bool allow_wildcard = true;
  WebPluginInfo info;
  FilePath plugin_path;
  if (NPAPI::PluginList::Singleton()->GetPluginInfo(
      url, mime_type, allow_wildcard, &info, NULL) && info.enabled) {
    plugin_path = info.path;
  }
  PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path);
  if (plugin_host) {
    plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
  } else {
    PluginProcessHost::ReplyToRenderer(
        renderer_msg_filter, IPC::ChannelHandle(), WebPluginInfo(), reply_msg);
  }
}

static void PurgePluginListCache(bool reload_pages) {
  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
       !it.IsAtEnd(); it.Advance()) {
    it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
  }
}

void PluginService::OnWaitableEventSignaled(
    base::WaitableEvent* waitable_event) {
#if defined(OS_WIN)
  if (waitable_event == hkcu_event_.get()) {
    hkcu_key_.StartWatching();
  } else {
    hklm_key_.StartWatching();
  }

  NPAPI::PluginList::Singleton()->RefreshPlugins();
  PurgePluginListCache(true);
#endif  // defined(OS_WIN)
}

static void ForceShutdownPlugin(const FilePath& plugin_path) {
  PluginProcessHost* plugin =
      PluginService::GetInstance()->FindPluginProcess(plugin_path);
  if (plugin)
    plugin->ForceShutdown();
}

void PluginService::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_[plugin.path] = extension->url();
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                               NewRunnableFunction(&ForceShutdownPlugin,
                                                   plugin.path));
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->RemoveExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_.erase(plugin.path);
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

#if defined(OS_MACOSX)
    case NotificationType::APP_ACTIVATED: {
      ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                             NewRunnableFunction(&NotifyPluginsOfActivation));
      break;
    }
#endif

    default:
      DCHECK(false);
  }
}

bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path,
                                               const GURL& url) {
  if (url.is_empty())
    return true;  // Caller wants all plugins.

  PrivatePluginMap::iterator it = private_plugins_.find(plugin_path);
  if (it == private_plugins_.end())
    return true;  // This plugin is not private, so it's allowed everywhere.

  // We do a dumb compare of scheme and host, rather than using the domain
  // service, since we only care about this for extensions.
  const GURL& required_url = it->second;
  return (url.scheme() == required_url.scheme() &&
          url.host() == required_url.host());
}

void PluginService::RegisterPepperPlugins() {
  std::vector<PepperPluginInfo> plugins;
  PepperPluginRegistry::GetList(&plugins);
  for (size_t i = 0; i < plugins.size(); ++i) {
    NPAPI::PluginVersionInfo info;
    info.path = plugins[i].path;
    info.product_name = plugins[i].name.empty() ?
        plugins[i].path.BaseName().ToWStringHack() :
        ASCIIToWide(plugins[i].name);
    info.file_description = ASCIIToWide(plugins[i].description);
    info.file_extensions = ASCIIToWide(plugins[i].file_extensions);
    info.file_description = ASCIIToWide(plugins[i].type_descriptions);
    info.mime_types = ASCIIToWide(JoinString(plugins[i].mime_types, '|'));

    // These NPAPI entry points will never be called.  TODO(darin): Come up
    // with a cleaner way to register pepper plugins with the NPAPI PluginList,
    // or perhaps refactor the PluginList to be less specific to NPAPI.
    memset(&info.entry_points, 0, sizeof(info.entry_points));

    NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
  }
}
<commit_msg>Purge renderer plug-in caches when a plug-in is enabled or disabled.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "build/build_config.h"

#include "chrome/browser/plugin_service.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/waitable_event.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_plugin_host.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_updater.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/chrome_plugin_lib.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/default_plugin.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/gpu_plugin.h"
#include "chrome/common/logging_chrome.h"
#include "chrome/common/notification_type.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pepper_plugin_registry.h"
#include "chrome/common/plugin_messages.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#ifndef DISABLE_NACL
#include "native_client/src/trusted/plugin/nacl_entry_points.h"
#endif
#include "webkit/glue/plugins/plugin_constants_win.h"
#include "webkit/glue/plugins/plugin_list.h"

#if defined(OS_MACOSX)
static void NotifyPluginsOfActivation() {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    plugin->OnAppActivation();
  }
}
#endif

// static
bool PluginService::enable_chrome_plugins_ = true;

void LoadPluginsFromDiskHook() {
  DCHECK(!ChromeThread::CurrentlyOn(ChromeThread::UI) &&
         !ChromeThread::CurrentlyOn(ChromeThread::IO)) <<
         "Can't load plugins on the IO/UI threads since it's very slow.";
}

// static
void PluginService::InitGlobalInstance(Profile* profile) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));

  NPAPI::PluginList::Singleton()->SetPluginLoadHook(LoadPluginsFromDiskHook);

  // We first group the plugins and then figure out which groups to disable.
  PluginUpdater::GetPluginUpdater()->DisablePluginGroupsFromPrefs(profile);

  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kDisableOutdatedPlugins)) {
    NPAPI::PluginList::Singleton()->DisableOutdatedPluginGroups();
  }

  // Have Chrome plugins write their data to the profile directory.
  GetInstance()->SetChromePluginDataDir(profile->GetPath());
}

// static
PluginService* PluginService::GetInstance() {
  return Singleton<PluginService>::get();
}

// static
void PluginService::EnableChromePlugins(bool enable) {
  enable_chrome_plugins_ = enable;
}

PluginService::PluginService()
    : main_message_loop_(MessageLoop::current()),
      resource_dispatcher_host_(NULL),
      ui_locale_(g_browser_process->GetApplicationLocale()) {
  RegisterPepperPlugins();

  // Have the NPAPI plugin list search for Chrome plugins as well.
  ChromePluginLib::RegisterPluginsWithNPAPI();

  // Load any specified on the command line as well.
  const CommandLine* command_line = CommandLine::ForCurrentProcess();
  FilePath path = command_line->GetSwitchValuePath(switches::kLoadPlugin);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  path = command_line->GetSwitchValuePath(switches::kExtraPluginDir);
  if (!path.empty())
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(path);

  chrome::RegisterInternalDefaultPlugin();

  // Register the internal Flash and PDF, if available.
  if (!CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableInternalFlash) &&
      PathService::Get(chrome::FILE_FLASH_PLUGIN, &path)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginPath(path);
  }

#ifndef DISABLE_NACL
  if (command_line->HasSwitch(switches::kInternalNaCl)) {
    RegisterInternalNaClPlugin();
  }
#endif

  chrome::RegisterInternalGPUPlugin();

#if defined(OS_WIN)
  hkcu_key_.Create(
      HKEY_CURRENT_USER, kRegistryMozillaPlugins, KEY_NOTIFY);
  hklm_key_.Create(
      HKEY_LOCAL_MACHINE, kRegistryMozillaPlugins, KEY_NOTIFY);
  if (hkcu_key_.StartWatching()) {
    hkcu_event_.reset(new base::WaitableEvent(hkcu_key_.watch_event()));
    hkcu_watcher_.StartWatching(hkcu_event_.get(), this);
  }

  if (hklm_key_.StartWatching()) {
    hklm_event_.reset(new base::WaitableEvent(hklm_key_.watch_event()));
    hklm_watcher_.StartWatching(hklm_event_.get(), this);
  }
#elif defined(OS_POSIX) && !defined(OS_MACOSX)
  // Also find plugins in a user-specific plugins dir,
  // e.g. ~/.config/chromium/Plugins.
  FilePath user_data_dir;
  if (PathService::Get(chrome::DIR_USER_DATA, &user_data_dir)) {
    NPAPI::PluginList::Singleton()->AddExtraPluginDir(
        user_data_dir.Append("Plugins"));
  }
#endif

  registrar_.Add(this, NotificationType::EXTENSION_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
#if defined(OS_MACOSX)
  // We need to know when the browser comes forward so we can bring modal plugin
  // windows forward too.
  registrar_.Add(this, NotificationType::APP_ACTIVATED,
                 NotificationService::AllSources());
#endif
  registrar_.Add(this, NotificationType::PLUGIN_ENABLE_STATUS_CHANGED,
                 NotificationService::AllSources());
}

PluginService::~PluginService() {
#if defined(OS_WIN)
  // Release the events since they're owned by RegKey, not WaitableEvent.
  hkcu_watcher_.StopWatching();
  hklm_watcher_.StopWatching();
  hkcu_event_->Release();
  hklm_event_->Release();
#endif
}

void PluginService::LoadChromePlugins(
    ResourceDispatcherHost* resource_dispatcher_host) {
  if (!enable_chrome_plugins_)
    return;

  resource_dispatcher_host_ = resource_dispatcher_host;
  ChromePluginLib::LoadChromePlugins(GetCPBrowserFuncsForBrowser());
}

void PluginService::SetChromePluginDataDir(const FilePath& data_dir) {
  chrome_plugin_data_dir_ = data_dir;
}

const FilePath& PluginService::GetChromePluginDataDir() {
  return chrome_plugin_data_dir_;
}

const std::string& PluginService::GetUILocale() {
  return ui_locale_;
}

PluginProcessHost* PluginService::FindPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  if (plugin_path.value().empty()) {
    NOTREACHED() << "should only be called if we have a plugin to load";
    return NULL;
  }

  for (BrowserChildProcessHost::Iterator iter(ChildProcessInfo::PLUGIN_PROCESS);
       !iter.Done(); ++iter) {
    PluginProcessHost* plugin = static_cast<PluginProcessHost*>(*iter);
    if (plugin->info().path == plugin_path)
      return plugin;
  }

  return NULL;
}

PluginProcessHost* PluginService::FindOrStartPluginProcess(
    const FilePath& plugin_path) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));

  PluginProcessHost *plugin_host = FindPluginProcess(plugin_path);
  if (plugin_host)
    return plugin_host;

  WebPluginInfo info;
  if (!NPAPI::PluginList::Singleton()->GetPluginInfoByPath(
          plugin_path, &info)) {
    DCHECK(false);
    return NULL;
  }

  // This plugin isn't loaded by any plugin process, so create a new process.
  plugin_host = new PluginProcessHost();
  if (!plugin_host->Init(info, ui_locale_)) {
    DCHECK(false);  // Init is not expected to fail
    delete plugin_host;
    return NULL;
  }

  return plugin_host;
}

void PluginService::OpenChannelToPlugin(
    ResourceMessageFilter* renderer_msg_filter,
    const GURL& url,
    const std::string& mime_type,
    const std::string& locale,
    IPC::Message* reply_msg) {
  DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
  bool allow_wildcard = true;
  WebPluginInfo info;
  FilePath plugin_path;
  if (NPAPI::PluginList::Singleton()->GetPluginInfo(
      url, mime_type, allow_wildcard, &info, NULL) && info.enabled) {
    plugin_path = info.path;
  }
  PluginProcessHost* plugin_host = FindOrStartPluginProcess(plugin_path);
  if (plugin_host) {
    plugin_host->OpenChannelToPlugin(renderer_msg_filter, mime_type, reply_msg);
  } else {
    PluginProcessHost::ReplyToRenderer(
        renderer_msg_filter, IPC::ChannelHandle(), WebPluginInfo(), reply_msg);
  }
}

static void PurgePluginListCache(bool reload_pages) {
  for (RenderProcessHost::iterator it = RenderProcessHost::AllHostsIterator();
       !it.IsAtEnd(); it.Advance()) {
    it.GetCurrentValue()->Send(new ViewMsg_PurgePluginListCache(reload_pages));
  }
}

void PluginService::OnWaitableEventSignaled(
    base::WaitableEvent* waitable_event) {
#if defined(OS_WIN)
  if (waitable_event == hkcu_event_.get()) {
    hkcu_key_.StartWatching();
  } else {
    hklm_key_.StartWatching();
  }

  NPAPI::PluginList::Singleton()->RefreshPlugins();
  PurgePluginListCache(true);
#endif  // defined(OS_WIN)
}

static void ForceShutdownPlugin(const FilePath& plugin_path) {
  PluginProcessHost* plugin =
      PluginService::GetInstance()->FindPluginProcess(plugin_path);
  if (plugin)
    plugin->ForceShutdown();
}

void PluginService::Observe(NotificationType type,
                            const NotificationSource& source,
                            const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSION_LOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_[plugin.path] = extension->url();
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      Extension* extension = Details<Extension>(details).ptr();
      bool plugins_changed = false;
      for (size_t i = 0; i < extension->plugins().size(); ++i) {
        const Extension::PluginInfo& plugin = extension->plugins()[i];
        ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                               NewRunnableFunction(&ForceShutdownPlugin,
                                                   plugin.path));
        NPAPI::PluginList::Singleton()->RefreshPlugins();
        NPAPI::PluginList::Singleton()->RemoveExtraPluginPath(plugin.path);
        plugins_changed = true;
        if (!plugin.is_public)
          private_plugins_.erase(plugin.path);
      }
      if (plugins_changed)
        PurgePluginListCache(false);
      break;
    }

#if defined(OS_MACOSX)
    case NotificationType::APP_ACTIVATED: {
      ChromeThread::PostTask(ChromeThread::IO, FROM_HERE,
                             NewRunnableFunction(&NotifyPluginsOfActivation));
      break;
    }
#endif

    case NotificationType::PLUGIN_ENABLE_STATUS_CHANGED: {
      PurgePluginListCache(false);
      break;
    }
    default:
      DCHECK(false);
  }
}

bool PluginService::PrivatePluginAllowedForURL(const FilePath& plugin_path,
                                               const GURL& url) {
  if (url.is_empty())
    return true;  // Caller wants all plugins.

  PrivatePluginMap::iterator it = private_plugins_.find(plugin_path);
  if (it == private_plugins_.end())
    return true;  // This plugin is not private, so it's allowed everywhere.

  // We do a dumb compare of scheme and host, rather than using the domain
  // service, since we only care about this for extensions.
  const GURL& required_url = it->second;
  return (url.scheme() == required_url.scheme() &&
          url.host() == required_url.host());
}

void PluginService::RegisterPepperPlugins() {
  std::vector<PepperPluginInfo> plugins;
  PepperPluginRegistry::GetList(&plugins);
  for (size_t i = 0; i < plugins.size(); ++i) {
    NPAPI::PluginVersionInfo info;
    info.path = plugins[i].path;
    info.product_name = plugins[i].name.empty() ?
        plugins[i].path.BaseName().ToWStringHack() :
        ASCIIToWide(plugins[i].name);
    info.file_description = ASCIIToWide(plugins[i].description);
    info.file_extensions = ASCIIToWide(plugins[i].file_extensions);
    info.file_description = ASCIIToWide(plugins[i].type_descriptions);
    info.mime_types = ASCIIToWide(JoinString(plugins[i].mime_types, '|'));

    // These NPAPI entry points will never be called.  TODO(darin): Come up
    // with a cleaner way to register pepper plugins with the NPAPI PluginList,
    // or perhaps refactor the PluginList to be less specific to NPAPI.
    memset(&info.entry_points, 0, sizeof(info.entry_points));

    NPAPI::PluginList::Singleton()->RegisterInternalPlugin(info);
  }
}
<|endoftext|>


<commit_before>#include "stdafx.h"

#include <SADXModLoader.h>
#include "minmax.h"

#include "input.h"
#include "rumble.h"
#include "DreamPad.h"

struct AnalogThing
{
	Angle angle;
	float magnitude;
};

DataArray(AnalogThing, NormalizedAnalogs, 0x03B0E7A0, 8);

namespace input
{
	ControllerData raw_input[GAMEPAD_COUNT];
	bool controller_enabled[GAMEPAD_COUNT];
	bool debug = false;

	void poll_controllers()
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				default:
					break;

				case SDL_CONTROLLERDEVICEADDED:
				{
					const int which = event.cdevice.which;
					for (uint i = 0; i < GAMEPAD_COUNT; i++)
					{
						// Checking for both in cases like the DualShock 4 and DS4Windows where the controller might be
						// "connected" twice with the same ID. DreamPad::Open automatically closes if already open.
						if (!DreamPad::controllers[i].connected() || DreamPad::controllers[i].controller_id() == which)
						{
							DreamPad::controllers[i].open(which);
							break;
						}
					}
					break;
				}

				case SDL_CONTROLLERDEVICEREMOVED:
				{
					const int which = event.cdevice.which;
					for (uint i = 0; i < GAMEPAD_COUNT; i++)
					{
						if (DreamPad::controllers[i].controller_id() == which)
						{
							DreamPad::controllers[i].close();
							break;
						}
					}
					break;
				}
			}
		}

		KeyboardMouse::poll();

		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			DreamPad& dreampad = DreamPad::controllers[i];

			dreampad.poll();
			dreampad.copy(raw_input[i]);

			// Compatibility for mods which use ControllersRaw directly.
			// This will only copy the first four controllers.
			if (i < ControllersRaw_Length)
			{
				ControllersRaw[i] = raw_input[i];
			}

#ifdef EXTENDED_BUTTONS
			if (debug && raw_input[i].HeldButtons & Buttons_C)
			{
				const ControllerData& pad = raw_input[i];
				Motor m = DreamPad::controllers[i].get_active_motor();

				DisplayDebugStringFormatted(NJM_LOCATION(0, 8 + (3 * i)), "P%d  B: %08X LT/RT: %03d/%03d V: %d%d", (i + 1),
					pad.HeldButtons, pad.LTriggerPressure, pad.RTriggerPressure, (m & Motor::large), (m & Motor::small) >> 1);
				DisplayDebugStringFormatted(NJM_LOCATION(4, 9 + (3 * i)), "LS: %4d/%4d (%f) RS: %4d/%4d (%f)",
					pad.LeftStickX, pad.LeftStickY, dreampad.normalized_l(), pad.RightStickX, pad.RightStickY, dreampad.normalized_r());

				if (pad.HeldButtons & Buttons_Z)
				{
					const int pressed = pad.PressedButtons;
					if (pressed & Buttons_Up)
					{
						dreampad.settings.rumble_factor += 0.125f;
					}
					else if (pressed & Buttons_Down)
					{
						dreampad.settings.rumble_factor -= 0.125f;
					}
					else if (pressed & Buttons_Left)
					{
						rumble::RumbleA(i, 0);
					}
					else if (pressed & Buttons_Right)
					{
						rumble::RumbleB(i, 7, 59, 6);
					}

					DisplayDebugStringFormatted(NJM_LOCATION(4, 10 + (3 * i)),
						"Rumble factor (U/D): %f (L/R to test)", dreampad.settings.rumble_factor);
				}
			}
#endif
		}
	}

	// ReSharper disable once CppDeclaratorNeverUsed
	static void WriteAnalogs_c()
	{
		if (!ControlEnabled)
		{
			return;
		}

		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			if (!controller_enabled[i])
			{
				continue;
			}

			const DreamPad& dream_pad = DreamPad::controllers[i];

			if (dream_pad.connected() || dream_pad.settings.allow_keyboard)
			{
				const ControllerData& pad = dream_pad.dreamcast_data();
				// SADX's internal deadzone is 12 of 127. It doesn't set the relative forward direction
				// unless this is exceeded in WriteAnalogs(), so the analog shouldn't be set otherwise.
				if (abs(pad.LeftStickX) > 12 || abs(pad.LeftStickY) > 12)
				{
					NormalizedAnalogs[i].magnitude = dream_pad.normalized_l();
				}
			}
		}
	}

	void __declspec(naked) WriteAnalogs_r()
	{
		__asm
		{
			call WriteAnalogs_c
			ret
		}
	}

	// ReSharper disable once CppDeclaratorNeverUsed
	static void redirect_raw_controllers()
	{
		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			ControllerPointers[i] = &raw_input[i];
		}
	}

	void __declspec(naked) InitRawControllers_hook()
	{
		__asm
		{
			call redirect_raw_controllers
			ret
		}
	}

	void EnableController_hook(Uint8 index)
	{
		// default behavior
		if (index > 1)
		{
			controller_enabled[0] = true;
			controller_enabled[1] = true;
		}

		if (index > GAMEPAD_COUNT)
		{
			for (Uint32 i = 0; i < min(index, static_cast<Uint8>(GAMEPAD_COUNT)); i++)
			{
				EnableController_hook(i);
			}
		}
		else
		{
			controller_enabled[index] = true;
		}
	}

	void DisableController_hook(Uint8 index)
	{
		// default behavior
		if (index > 1)
		{
			controller_enabled[0] = false;
			controller_enabled[1] = false;
		}

		if (index > GAMEPAD_COUNT)
		{
			for (Uint32 i = 0; i < min(index, static_cast<Uint8>(GAMEPAD_COUNT)); i++)
			{
				DisableController_hook(i);
			}
		}
		else
		{
			controller_enabled[index] = false;
		}
	}
}
<commit_msg>let's just ensure this is only working for player 1<commit_after>#include "stdafx.h"

#include <SADXModLoader.h>
#include "minmax.h"

#include "input.h"
#include "rumble.h"
#include "DreamPad.h"

struct AnalogThing
{
	Angle angle;
	float magnitude;
};

DataArray(AnalogThing, NormalizedAnalogs, 0x03B0E7A0, 8);

namespace input
{
	ControllerData raw_input[GAMEPAD_COUNT];
	bool controller_enabled[GAMEPAD_COUNT];
	bool debug = false;

	void poll_controllers()
	{
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				default:
					break;

				case SDL_CONTROLLERDEVICEADDED:
				{
					const int which = event.cdevice.which;
					for (uint i = 0; i < GAMEPAD_COUNT; i++)
					{
						// Checking for both in cases like the DualShock 4 and DS4Windows where the controller might be
						// "connected" twice with the same ID. DreamPad::Open automatically closes if already open.
						if (!DreamPad::controllers[i].connected() || DreamPad::controllers[i].controller_id() == which)
						{
							DreamPad::controllers[i].open(which);
							break;
						}
					}
					break;
				}

				case SDL_CONTROLLERDEVICEREMOVED:
				{
					const int which = event.cdevice.which;
					for (uint i = 0; i < GAMEPAD_COUNT; i++)
					{
						if (DreamPad::controllers[i].controller_id() == which)
						{
							DreamPad::controllers[i].close();
							break;
						}
					}
					break;
				}
			}
		}

		KeyboardMouse::poll();

		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			DreamPad& dreampad = DreamPad::controllers[i];

			dreampad.poll();
			dreampad.copy(raw_input[i]);

			// Compatibility for mods which use ControllersRaw directly.
			// This will only copy the first four controllers.
			if (i < ControllersRaw_Length)
			{
				ControllersRaw[i] = raw_input[i];
			}

#ifdef EXTENDED_BUTTONS
			if (debug && raw_input[i].HeldButtons & Buttons_C)
			{
				const ControllerData& pad = raw_input[i];
				Motor m = DreamPad::controllers[i].get_active_motor();

				DisplayDebugStringFormatted(NJM_LOCATION(0, 8 + (3 * i)), "P%d  B: %08X LT/RT: %03d/%03d V: %d%d", (i + 1),
					pad.HeldButtons, pad.LTriggerPressure, pad.RTriggerPressure, (m & Motor::large), (m & Motor::small) >> 1);
				DisplayDebugStringFormatted(NJM_LOCATION(4, 9 + (3 * i)), "LS: %4d/%4d (%f) RS: %4d/%4d (%f)",
					pad.LeftStickX, pad.LeftStickY, dreampad.normalized_l(), pad.RightStickX, pad.RightStickY, dreampad.normalized_r());

				if (pad.HeldButtons & Buttons_Z)
				{
					const int pressed = pad.PressedButtons;
					if (pressed & Buttons_Up)
					{
						dreampad.settings.rumble_factor += 0.125f;
					}
					else if (pressed & Buttons_Down)
					{
						dreampad.settings.rumble_factor -= 0.125f;
					}
					else if (pressed & Buttons_Left)
					{
						rumble::RumbleA(i, 0);
					}
					else if (pressed & Buttons_Right)
					{
						rumble::RumbleB(i, 7, 59, 6);
					}

					DisplayDebugStringFormatted(NJM_LOCATION(4, 10 + (3 * i)),
						"Rumble factor (U/D): %f (L/R to test)", dreampad.settings.rumble_factor);
				}
			}
#endif
		}
	}

	// ReSharper disable once CppDeclaratorNeverUsed
	static void WriteAnalogs_c()
	{
		if (!ControlEnabled)
		{
			return;
		}

		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			if (!controller_enabled[i])
			{
				continue;
			}

			const DreamPad& dream_pad = DreamPad::controllers[i];

			if (dream_pad.connected() || dream_pad.settings.allow_keyboard && !i)
			{
				const ControllerData& pad = dream_pad.dreamcast_data();
				// SADX's internal deadzone is 12 of 127. It doesn't set the relative forward direction
				// unless this is exceeded in WriteAnalogs(), so the analog shouldn't be set otherwise.
				if (abs(pad.LeftStickX) > 12 || abs(pad.LeftStickY) > 12)
				{
					NormalizedAnalogs[i].magnitude = dream_pad.normalized_l();
				}
			}
		}
	}

	void __declspec(naked) WriteAnalogs_r()
	{
		__asm
		{
			call WriteAnalogs_c
			ret
		}
	}

	// ReSharper disable once CppDeclaratorNeverUsed
	static void redirect_raw_controllers()
	{
		for (uint i = 0; i < GAMEPAD_COUNT; i++)
		{
			ControllerPointers[i] = &raw_input[i];
		}
	}

	void __declspec(naked) InitRawControllers_hook()
	{
		__asm
		{
			call redirect_raw_controllers
			ret
		}
	}

	void EnableController_hook(Uint8 index)
	{
		// default behavior
		if (index > 1)
		{
			controller_enabled[0] = true;
			controller_enabled[1] = true;
		}

		if (index > GAMEPAD_COUNT)
		{
			for (Uint32 i = 0; i < min(index, static_cast<Uint8>(GAMEPAD_COUNT)); i++)
			{
				EnableController_hook(i);
			}
		}
		else
		{
			controller_enabled[index] = true;
		}
	}

	void DisableController_hook(Uint8 index)
	{
		// default behavior
		if (index > 1)
		{
			controller_enabled[0] = false;
			controller_enabled[1] = false;
		}

		if (index > GAMEPAD_COUNT)
		{
			for (Uint32 i = 0; i < min(index, static_cast<Uint8>(GAMEPAD_COUNT)); i++)
			{
				DisableController_hook(i);
			}
		}
		else
		{
			controller_enabled[index] = false;
		}
	}
}
<|endoftext|>


<commit_before>#include "ExecutionEngine.h"

#include <array>
#include <mutex>
#include <iostream>

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"

#include "Runtime.h"
#include "Compiler.h"
#include "Optimizer.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace
{
using EntryFuncPtr = ReturnCode(*)(Runtime*);

std::string codeHash(i256 const& _hash)
{
	static const auto size = sizeof(_hash);
	static const auto hexChars = "0123456789abcdef";
	std::string str;
	str.resize(size * 2);
	auto outIt = str.rbegin(); // reverse for BE
	auto& arr = *(std::array<byte, size>*)&_hash;
	for (auto b : arr)
	{
		*(outIt++) = hexChars[b & 0xf];
		*(outIt++) = hexChars[b >> 4];
	}
	return str;
}

void printVersion()
{
	std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
			  << "  EVMJIT version " << EVMJIT_VERSION << "\n"
#ifdef NDEBUG
			  << "  Optimized build, " EVMJIT_VERSION_FULL "\n"
#else
			  << "  DEBUG build, " EVMJIT_VERSION_FULL "\n"
#endif
			  << "  Built " << __DATE__ << " (" << __TIME__ << ")\n"
			  << std::endl;
}

namespace cl = llvm::cl;
cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
cl::opt<bool> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"}, cl::init(true)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};

void parseOptions()
{
	static llvm::llvm_shutdown_obj shutdownObj{};
	cl::AddExtraVersionPrinter(printVersion);
	cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
}

}

ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{
	static std::once_flag flag;
	std::call_once(flag, parseOptions);

	std::unique_ptr<ExecStats> listener{new ExecStats};
	listener->stateChanged(ExecState::Started);

	auto objectCache = g_cache ? Cache::getObjectCache(listener.get()) : nullptr;

	static std::unique_ptr<llvm::ExecutionEngine> ee;
	if (!ee)
	{
		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext()));
		llvm::EngineBuilder builder(module.get());
		builder.setEngineKind(llvm::EngineKind::JIT);
		builder.setUseMCJIT(true);
		builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);

		auto triple = llvm::Triple(llvm::sys::getProcessTriple());
		if (triple.getOS() == llvm::Triple::OSType::Win32)
			triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
		module->setTargetTriple(triple.str());

		ee.reset(builder.create());
		if (!CHECK(ee))
			return ReturnCode::LLVMConfigError;
		module.release();  // Successfully created llvm::ExecutionEngine takes ownership of the module
		ee->setObjectCache(objectCache);
	}

	static StatsCollector statsCollector;

	auto mainFuncName = codeHash(_data->codeHash);
	m_runtime.init(_data, _env);

	auto entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	if (!entryFuncPtr)
	{
		auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
		if (!module)
		{
			listener->stateChanged(ExecState::Compilation);
			assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code?
			module = Compiler{{}}.compile(_data->code, _data->code + _data->codeSize, mainFuncName);

			if (g_optimize)
			{
				listener->stateChanged(ExecState::Optimization);
				optimize(*module);
			}
		}
		if (g_dump)
			module->dump();

		ee->addModule(module.get());
		module.release();
		listener->stateChanged(ExecState::CodeGen);
		entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	}
	if (!CHECK(entryFuncPtr))
		return ReturnCode::LLVMLinkError;

	listener->stateChanged(ExecState::Execution);
	auto returnCode = entryFuncPtr(&m_runtime);
	listener->stateChanged(ExecState::Return);

	if (returnCode == ReturnCode::Return)
		returnData = m_runtime.getReturnData();     // Save reference to return data

	listener->stateChanged(ExecState::Finished);

	if (g_stats)
		statsCollector.stats.push_back(std::move(listener));

	return returnCode;
}

}
}
}
<commit_msg>Cache pointers for emited functions<commit_after>#include "ExecutionEngine.h"

#include <array>
#include <mutex>
#include <iostream>
#include <unordered_map>

#include "preprocessor/llvm_includes_start.h"
#include <llvm/IR/Module.h>
#include <llvm/ADT/Triple.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ManagedStatic.h>
#include "preprocessor/llvm_includes_end.h"

#include "Runtime.h"
#include "Compiler.h"
#include "Optimizer.h"
#include "Cache.h"
#include "ExecStats.h"
#include "Utils.h"
#include "BuildInfo.gen.h"

namespace dev
{
namespace eth
{
namespace jit
{

namespace
{
using EntryFuncPtr = ReturnCode(*)(Runtime*);

std::string codeHash(i256 const& _hash)
{
	static const auto size = sizeof(_hash);
	static const auto hexChars = "0123456789abcdef";
	std::string str;
	str.resize(size * 2);
	auto outIt = str.rbegin(); // reverse for BE
	auto& arr = *(std::array<byte, size>*)&_hash;
	for (auto b : arr)
	{
		*(outIt++) = hexChars[b & 0xf];
		*(outIt++) = hexChars[b >> 4];
	}
	return str;
}

void printVersion()
{
	std::cout << "Ethereum EVM JIT Compiler (http://github.com/ethereum/evmjit):\n"
			  << "  EVMJIT version " << EVMJIT_VERSION << "\n"
#ifdef NDEBUG
			  << "  Optimized build, " EVMJIT_VERSION_FULL "\n"
#else
			  << "  DEBUG build, " EVMJIT_VERSION_FULL "\n"
#endif
			  << "  Built " << __DATE__ << " (" << __TIME__ << ")\n"
			  << std::endl;
}

namespace cl = llvm::cl;
cl::opt<bool> g_optimize{"O", cl::desc{"Optimize"}};
cl::opt<bool> g_cache{"cache", cl::desc{"Cache compiled EVM code on disk"}, cl::init(true)};
cl::opt<bool> g_stats{"st", cl::desc{"Statistics"}};
cl::opt<bool> g_dump{"dump", cl::desc{"Dump LLVM IR module"}};

void parseOptions()
{
	static llvm::llvm_shutdown_obj shutdownObj{};
	cl::AddExtraVersionPrinter(printVersion);
	cl::ParseEnvironmentOptions("evmjit", "EVMJIT", "Ethereum EVM JIT Compiler");
}

}

ReturnCode ExecutionEngine::run(RuntimeData* _data, Env* _env)
{
	static std::once_flag flag;
	std::call_once(flag, parseOptions);

	std::unique_ptr<ExecStats> listener{new ExecStats};
	listener->stateChanged(ExecState::Started);

	auto objectCache = g_cache ? Cache::getObjectCache(listener.get()) : nullptr;

	static std::unique_ptr<llvm::ExecutionEngine> ee;
	if (!ee)
	{
		llvm::InitializeNativeTarget();
		llvm::InitializeNativeTargetAsmPrinter();

		auto module = std::unique_ptr<llvm::Module>(new llvm::Module({}, llvm::getGlobalContext()));
		llvm::EngineBuilder builder(module.get());
		builder.setEngineKind(llvm::EngineKind::JIT);
		builder.setUseMCJIT(true);
		builder.setOptLevel(g_optimize ? llvm::CodeGenOpt::Default : llvm::CodeGenOpt::None);

		auto triple = llvm::Triple(llvm::sys::getProcessTriple());
		if (triple.getOS() == llvm::Triple::OSType::Win32)
			triple.setObjectFormat(llvm::Triple::ObjectFormatType::ELF);  // MCJIT does not support COFF format
		module->setTargetTriple(triple.str());

		ee.reset(builder.create());
		if (!CHECK(ee))
			return ReturnCode::LLVMConfigError;
		module.release();  // Successfully created llvm::ExecutionEngine takes ownership of the module
		ee->setObjectCache(objectCache);
	}

	static StatsCollector statsCollector;

	auto mainFuncName = codeHash(_data->codeHash);
	m_runtime.init(_data, _env);

	EntryFuncPtr entryFuncPtr = nullptr;
	static std::unordered_map<std::string, EntryFuncPtr> funcCache;
	auto it = funcCache.find(mainFuncName);
	if (it != funcCache.end())
		entryFuncPtr = it->second;

	if (!entryFuncPtr)
	{
		auto module = objectCache ? Cache::getObject(mainFuncName) : nullptr;
		if (!module)
		{
			listener->stateChanged(ExecState::Compilation);
			assert(_data->code || !_data->codeSize); //TODO: Is it good idea to execute empty code?
			module = Compiler{{}}.compile(_data->code, _data->code + _data->codeSize, mainFuncName);

			if (g_optimize)
			{
				listener->stateChanged(ExecState::Optimization);
				optimize(*module);
			}
		}
		if (g_dump)
			module->dump();

		ee->addModule(module.get());
		module.release();
		listener->stateChanged(ExecState::CodeGen);
		entryFuncPtr = (EntryFuncPtr)ee->getFunctionAddress(mainFuncName);
	}
	if (!CHECK(entryFuncPtr))
		return ReturnCode::LLVMLinkError;

	funcCache[mainFuncName] = entryFuncPtr;

	listener->stateChanged(ExecState::Execution);
	auto returnCode = entryFuncPtr(&m_runtime);
	listener->stateChanged(ExecState::Return);

	if (returnCode == ReturnCode::Return)
		returnData = m_runtime.getReturnData();     // Save reference to return data

	listener->stateChanged(ExecState::Finished);

	if (g_stats)
		statsCollector.stats.push_back(std::move(listener));

	return returnCode;
}

}
}
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: macro.hxx,v $
 * $Revision: 1.16 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _RTL_MACRO_HXX
#define _RTL_MACRO_HXX

#include <rtl/bootstrap.h>
#include <rtl/ustring.hxx>
#include <osl/endian.h>

#if defined WIN32
#define THIS_OS "Windows"
#elif defined OS2
#define THIS_OS "OS2"
#elif defined SOLARIS
#define THIS_OS "Solaris"
#elif defined LINUX
#define THIS_OS "Linux"
#elif defined MACOSX
#define THIS_OS "MacOSX"
#elif defined NETBSD
#define THIS_OS "NetBSD"
#elif defined FREEBSD
#define THIS_OS "FreeBSD"
#elif defined IRIX
#define THIS_OS "Irix"
#endif

#if ! defined THIS_OS
#error "unknown OS -- insert your OS identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#if defined X86_64
#    define THIS_ARCH "X86_64"
#elif defined INTEL
#    define THIS_ARCH "x86"
#elif defined POWERPC64
#    define THIS_ARCH "PowerPC_64"
#elif defined POWERPC
#    define THIS_ARCH "PowerPC"
#elif defined S390X
#    define THIS_ARCH "S390x"
#elif defined S390
#    define THIS_ARCH "S390"
#elif defined SPARC
#    define THIS_ARCH "SPARC"
#elif defined SPARC64
#    define THIS_ARCH "SPARC64"
#elif defined IRIX
#    define THIS_ARCH "MIPS"
#elif defined MIPS
#    ifdef OSL_BIGENDIAN
#        define THIS_ARCH "MIPS_EB"
#    else
#        define THIS_ARCH "MIPS_EL"
#    endif
#elif defined ARM
#    ifdef __ARM_EABI__
#        define THIS_ARCH "ARM_EABI"
#    else
#        define THIS_ARCH "ARM_OABI"
#    endif
#elif defined IA64
#    define THIS_ARCH "IA64"
#elif defined M68K
#    define THIS_ARCH "M68K"
#endif

#if ! defined THIS_ARCH
#error "unknown ARCH -- insert your ARCH identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#endif

<commit_msg>INTEGRATION: CWS sb91 (1.14.2); FILE MERGED 2008/07/16 06:49:52 sb 1.14.2.1: #i91567# SPARC64 was tentative; has been replaced by SPARC + IS_LP64<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: macro.hxx,v $
 * $Revision: 1.17 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _RTL_MACRO_HXX
#define _RTL_MACRO_HXX

#include <rtl/bootstrap.h>
#include <rtl/ustring.hxx>
#include <osl/endian.h>

#if defined WIN32
#define THIS_OS "Windows"
#elif defined OS2
#define THIS_OS "OS2"
#elif defined SOLARIS
#define THIS_OS "Solaris"
#elif defined LINUX
#define THIS_OS "Linux"
#elif defined MACOSX
#define THIS_OS "MacOSX"
#elif defined NETBSD
#define THIS_OS "NetBSD"
#elif defined FREEBSD
#define THIS_OS "FreeBSD"
#elif defined IRIX
#define THIS_OS "Irix"
#endif

#if ! defined THIS_OS
#error "unknown OS -- insert your OS identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#if defined X86_64
#    define THIS_ARCH "X86_64"
#elif defined INTEL
#    define THIS_ARCH "x86"
#elif defined POWERPC64
#    define THIS_ARCH "PowerPC_64"
#elif defined POWERPC
#    define THIS_ARCH "PowerPC"
#elif defined S390X
#    define THIS_ARCH "S390x"
#elif defined S390
#    define THIS_ARCH "S390"
#elif defined SPARC
#if defined IS_LP64
#    define THIS_ARCH "SPARC64"
#else
#    define THIS_ARCH "SPARC"
#endif
#elif defined IRIX
#    define THIS_ARCH "MIPS"
#elif defined MIPS
#    ifdef OSL_BIGENDIAN
#        define THIS_ARCH "MIPS_EB"
#    else
#        define THIS_ARCH "MIPS_EL"
#    endif
#elif defined ARM
#    ifdef __ARM_EABI__
#        define THIS_ARCH "ARM_EABI"
#    else
#        define THIS_ARCH "ARM_OABI"
#    endif
#elif defined IA64
#    define THIS_ARCH "IA64"
#elif defined M68K
#    define THIS_ARCH "M68K"
#endif

#if ! defined THIS_ARCH
#error "unknown ARCH -- insert your ARCH identifier above"
this is inserted for the case that the preprocessor ignores error
#endif

#endif

<|endoftext|>


<commit_before>/** @file

  WebSocket termination example.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF 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 "WSBuffer.h"

#include <ts/ts.h>
#include <ts/ink_config.h>
#include "openssl/evp.h"
#include <netinet/in.h>
#include <arpa/inet.h>

#if defined(__linux__)
#include <endian.h>
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define be64toh(x) OSSwapBigToHostInt64(x)
#elif defined(sun) || defined(__sun)
#if BYTE_ORDER == LITTLE_ENDIAN
#define be64toh(x) ntohll(x)
#elif BYTE_ORDER == BIG_ENDIAN
#define be64toh(x) (x)
#endif
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__DragonFly__)
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN
#define be64toh(x) __bswap64(x)
#elif BYTE_ORDER == BIG_ENDIAN
#define be64toh(x) (x)
#endif
#endif

#define BASE64_ENCODE_DSTLEN(_length) ((_length * 8) / 6 + 4)
#define WS_DIGEST_MAX BASE64_ENCODE_DSTLEN(20)

static const std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

WSBuffer::WSBuffer() : frame_(0)
{
}

void
WSBuffer::buffer(std::string const &data)
{
  ws_buf_ += data;
}

bool
WSBuffer::read_buffered_message(std::string &message, int &code)
{
  // There are two basic states depending on whether or
  // not we have parsed a message length. If we're looking
  // for a message length, we don't advance pos_ until we
  // have read one (as well as control bytes and mask).
  //
  // Once we have a message length, we don't advance
  // pos_ until we have a complete message. (If the message
  // length is 0 we will produce the message immediately
  // and revert to looking for the next message length.)
  //
  // When incoming data is fragmented we may be called several
  // times before we get a length or a complete message.

  char mask[4];

  size_t avail = ws_buf_.size();

  // Check if there is a mask (there should be).
  if (avail < 2)
    return false;
  size_t mask_len = (ws_buf_[1] & WS_MASKED) ? 4 : 0;

  int frame  = ws_buf_[0] & WS_OPCODE;
  bool first = frame != WS_FRAME_CONTINUATION;
  auto final = ws_buf_[0] & WS_FIN;

  // Save/restore frame type on first/continuation.
  if (first) {
    frame_ = frame;
    msg_buf_.clear();
  } else
    frame = frame_;

  // Read the msg_length if we have enough data.
  if (avail < 2 + mask_len)
    return false;

  size_t msg_len = ws_buf_[1] & WS_LENGTH;
  size_t pos;
  if (msg_len == WS_16BIT_LEN) {
    if (avail < 4 + mask_len) { // 2 + 2 + length bytes + mask.
      return false;
    }
    msg_len = ntohs(*(uint16_t *)(ws_buf_.data() + 2));
    pos     = 4;
  } else if (msg_len == WS_64BIT_LEN) {
    if (avail < 10 + mask_len) { // 2 + 8 length bytes + mask.
      return false;
    }
    msg_len = be64toh(*(uint64_t *)(ws_buf_.data() + 2));
    pos     = 10;
  } else {
    pos = 2;
  }

  // Check if we have enough data to read the message.
  if (ws_buf_.size() < pos + msg_len)
    return false; // not enough data.

  // Copy any mask.
  for (size_t i = 0; i < mask_len; ++i, ++pos) {
    mask[i] = ws_buf_[pos];
  }

  // Apply any mask.
  if (mask_len) {
    for (size_t i = 0, p = pos; i < msg_len; ++i, ++p) {
      ws_buf_[p] ^= mask[i & 3];
    }
  }

  // Copy the message out.
  if (final) {
    message = msg_buf_;
    message += ws_buf_.substr(pos, msg_len);
    code = frame;
  } else {
    msg_buf_ += ws_buf_.substr(pos, msg_len);
  }

  // Discard consumed data.
  ws_buf_.erase(0, pos + msg_len);

  return true;
}

std::string
WSBuffer::ws_digest(std::string const &key)
{
  EVP_MD_CTX *digest = EVP_MD_CTX_new();

  if (!EVP_DigestInit_ex(digest, EVP_sha1(), nullptr)) {
    EVP_MD_CTX_free(digest);
    return "init-failed";
  }
  if (!EVP_DigestUpdate(digest, key.data(), key.length())) {
    EVP_MD_CTX_free(digest);
    return "update1-failed";
  }
  if (!EVP_DigestUpdate(digest, magic.data(), magic.length())) {
    EVP_MD_CTX_free(digest);
    return "update2-failed";
  }

  unsigned char hash_buf[EVP_MAX_MD_SIZE];
  unsigned int hash_len = 0;
  if (!EVP_DigestFinal_ex(digest, hash_buf, &hash_len)) {
    EVP_MD_CTX_free(digest);
    return "final-failed";
  }
  EVP_MD_CTX_free(digest);
  if (hash_len != 20) {
    return "bad-hash-length";
  }

  char digest_buf[WS_DIGEST_MAX];
  size_t digest_len = 0;

  if (TSBase64Encode((char *)hash_buf, hash_len, digest_buf, WS_DIGEST_MAX, &digest_len) != TS_SUCCESS) {
    return "base64encode-failed";
  }

  return std::string((char *)digest_buf, digest_len);
}

std::string
WSBuffer::get_handshake(std::string const &ws_key)
{
  std::string digest = ws_digest(ws_key);

  // NOTE: a real server might be expecting a Sec-WebSocket-Protocol
  // header and wish to respond accordingly. In that case you must
  // call ws_digest() and construct the headers yourself.

  std::string headers = "HTTP/1.1 101 Switching Protocols\r\n"
                        "Upgrade: websocket\r\n"
                        "Connection: Upgrade\r\n"
                        "Sec-WebSocket-Accept: " +
                        digest + "\r\n\r\n";
  return headers;
}

std::string
WSBuffer::get_frame(size_t len, int code)
{
  std::string frame;
  frame.reserve(10);
  frame += char(code);

  int len_len;
  if (len <= 125) {
    frame += char(len);
    len_len = 0;
  } else if (len <= UINT16_MAX) {
    frame += char(WS_16BIT_LEN);
    len_len = 2;
  } else {
    frame += char(WS_64BIT_LEN);
    len_len = 8;
  }
  // Convert length to big-endian bytes.
  while (--len_len >= 0) {
    frame += char((len >> (8 * len_len)) & 0xFF);
  }

  return frame;
}

uint16_t
WSBuffer::get_closing_code(std::string const &message, std::string *desc)
{
  uint16_t code = 0;
  if (message.size() >= 2) {
    code = (unsigned char)message[0];
    code <<= 8;
    code += (unsigned char)message[1];
    if (desc)
      *desc = message.substr(2);
  } else {
    if (desc)
      *desc = "";
  }
  return code;
}
<commit_msg>Coverity 1373301: Untrusted loop bound<commit_after>/** @file

  WebSocket termination example.

  @section license License

  Licensed to the Apache Software Foundation (ASF) under one
  or more contributor license agreements.  See the NOTICE file
  distributed with this work for additional information
  regarding copyright ownership.  The ASF 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 "WSBuffer.h"

#include <ts/ts.h>
#include <ts/ink_config.h>
#include "openssl/evp.h"
#include <netinet/in.h>
#include <arpa/inet.h>

#if defined(__linux__)
#include <endian.h>
#elif defined(__APPLE__)
#include <libkern/OSByteOrder.h>
#define be64toh(x) OSSwapBigToHostInt64(x)
#elif defined(sun) || defined(__sun)
#if BYTE_ORDER == LITTLE_ENDIAN
#define be64toh(x) ntohll(x)
#elif BYTE_ORDER == BIG_ENDIAN
#define be64toh(x) (x)
#endif
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__DragonFly__)
#include <machine/endian.h>
#if BYTE_ORDER == LITTLE_ENDIAN
#define be64toh(x) __bswap64(x)
#elif BYTE_ORDER == BIG_ENDIAN
#define be64toh(x) (x)
#endif
#endif

#define BASE64_ENCODE_DSTLEN(_length) ((_length * 8) / 6 + 4)
#define WS_DIGEST_MAX BASE64_ENCODE_DSTLEN(20)

static const std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";

WSBuffer::WSBuffer() : frame_(0)
{
}

void
WSBuffer::buffer(std::string const &data)
{
  ws_buf_ += data;
}

bool
WSBuffer::read_buffered_message(std::string &message, int &code)
{
  // There are two basic states depending on whether or
  // not we have parsed a message length. If we're looking
  // for a message length, we don't advance pos_ until we
  // have read one (as well as control bytes and mask).
  //
  // Once we have a message length, we don't advance
  // pos_ until we have a complete message. (If the message
  // length is 0 we will produce the message immediately
  // and revert to looking for the next message length.)
  //
  // When incoming data is fragmented we may be called several
  // times before we get a length or a complete message.

  char mask[4];

  size_t avail = ws_buf_.size();

  // Check if there is a mask (there should be).
  if (avail < 2)
    return false;
  size_t mask_len = (ws_buf_[1] & WS_MASKED) ? 4 : 0;

  int frame  = ws_buf_[0] & WS_OPCODE;
  bool first = frame != WS_FRAME_CONTINUATION;
  auto final = ws_buf_[0] & WS_FIN;

  // Save/restore frame type on first/continuation.
  if (first) {
    frame_ = frame;
    msg_buf_.clear();
  } else
    frame = frame_;

  // Read the msg_length if we have enough data.
  if (avail < 2 + mask_len)
    return false;

  size_t msg_len = ws_buf_[1] & WS_LENGTH;
  size_t pos;
  if (msg_len == WS_16BIT_LEN) {
    if (avail < 4 + mask_len) { // 2 + 2 + length bytes + mask.
      return false;
    }
    msg_len = ntohs(*(uint16_t *)(ws_buf_.data() + 2));
    pos     = 4;
  } else if (msg_len == WS_64BIT_LEN) {
    if (avail < 10 + mask_len) { // 2 + 8 length bytes + mask.
      return false;
    }
    msg_len = be64toh(*(uint64_t *)(ws_buf_.data() + 2));
    pos     = 10;
  } else {
    pos = 2;
  }

  // Check if we have enough data to read the message.
  if (ws_buf_.size() < pos + msg_len)
    return false; // not enough data.

  // Copy any mask.
  for (size_t i = 0; i < mask_len; ++i, ++pos) {
    mask[i] = ws_buf_[pos];
  }

  // Apply any mask.
  if (mask_len) {
    for (size_t i = 0, p = pos; i < msg_len && p < ws_buf_.size(); ++i, ++p) {
      ws_buf_[p] ^= mask[i & 3];
    }
  }

  // Copy the message out.
  if (final) {
    message = msg_buf_;
    message += ws_buf_.substr(pos, msg_len);
    code = frame;
  } else {
    msg_buf_ += ws_buf_.substr(pos, msg_len);
  }

  // Discard consumed data.
  ws_buf_.erase(0, pos + msg_len);

  return true;
}

std::string
WSBuffer::ws_digest(std::string const &key)
{
  EVP_MD_CTX *digest = EVP_MD_CTX_new();

  if (!EVP_DigestInit_ex(digest, EVP_sha1(), nullptr)) {
    EVP_MD_CTX_free(digest);
    return "init-failed";
  }
  if (!EVP_DigestUpdate(digest, key.data(), key.length())) {
    EVP_MD_CTX_free(digest);
    return "update1-failed";
  }
  if (!EVP_DigestUpdate(digest, magic.data(), magic.length())) {
    EVP_MD_CTX_free(digest);
    return "update2-failed";
  }

  unsigned char hash_buf[EVP_MAX_MD_SIZE];
  unsigned int hash_len = 0;
  if (!EVP_DigestFinal_ex(digest, hash_buf, &hash_len)) {
    EVP_MD_CTX_free(digest);
    return "final-failed";
  }
  EVP_MD_CTX_free(digest);
  if (hash_len != 20) {
    return "bad-hash-length";
  }

  char digest_buf[WS_DIGEST_MAX];
  size_t digest_len = 0;

  if (TSBase64Encode((char *)hash_buf, hash_len, digest_buf, WS_DIGEST_MAX, &digest_len) != TS_SUCCESS) {
    return "base64encode-failed";
  }

  return std::string((char *)digest_buf, digest_len);
}

std::string
WSBuffer::get_handshake(std::string const &ws_key)
{
  std::string digest = ws_digest(ws_key);

  // NOTE: a real server might be expecting a Sec-WebSocket-Protocol
  // header and wish to respond accordingly. In that case you must
  // call ws_digest() and construct the headers yourself.

  std::string headers = "HTTP/1.1 101 Switching Protocols\r\n"
                        "Upgrade: websocket\r\n"
                        "Connection: Upgrade\r\n"
                        "Sec-WebSocket-Accept: " +
                        digest + "\r\n\r\n";
  return headers;
}

std::string
WSBuffer::get_frame(size_t len, int code)
{
  std::string frame;
  frame.reserve(10);
  frame += char(code);

  int len_len;
  if (len <= 125) {
    frame += char(len);
    len_len = 0;
  } else if (len <= UINT16_MAX) {
    frame += char(WS_16BIT_LEN);
    len_len = 2;
  } else {
    frame += char(WS_64BIT_LEN);
    len_len = 8;
  }
  // Convert length to big-endian bytes.
  while (--len_len >= 0) {
    frame += char((len >> (8 * len_len)) & 0xFF);
  }

  return frame;
}

uint16_t
WSBuffer::get_closing_code(std::string const &message, std::string *desc)
{
  uint16_t code = 0;
  if (message.size() >= 2) {
    code = (unsigned char)message[0];
    code <<= 8;
    code += (unsigned char)message[1];
    if (desc)
      *desc = message.substr(2);
  } else {
    if (desc)
      *desc = "";
  }
  return code;
}
<|endoftext|>