Browse Source

Initial commit

Adam Roben 12 years ago
commit
e451d92121

+ 2 - 0
brightray/.gitignore

@@ -0,0 +1,2 @@
+/brightray.xcodeproj/
+/build/

+ 3 - 0
brightray/.gitmodules

@@ -0,0 +1,3 @@
+[submodule "vendor/libchromiumcontent"]
+	path = vendor/libchromiumcontent
+	url = https://github.com/aroben/libchromiumcontent

+ 19 - 0
brightray/LICENSE

@@ -0,0 +1,19 @@
+Copyright (c) 2013 Adam Roben <[email protected]>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 27 - 0
brightray/LICENSE-CHROMIUM

@@ -0,0 +1,27 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 34 - 0
brightray/README.md

@@ -0,0 +1,34 @@
+# Brightray
+
+Brightray is a static library that makes
+[libchromiumcontent](https://github.com/aroben/libchromiumcontent) easier to
+use in applications.
+
+## Using it in your app
+
+See [brightray_example](https://github.com/aroben/brightray_example) for a
+sample application written using Brightray.
+
+## Development
+
+### One-time setup
+
+You must previously have built and uploaded libchromiumcontent using its
+`script/upload` script.
+
+    $ script/bootstrap http://base.url.com/used/by/script/upload
+
+### Building
+
+    $ script/build
+
+Building Brightray on its own isn’t all that interesting, since it’s just a
+static library. Building it into an application (like
+[brightray_example](https://github.com/aroben/brightray_example)) is the only
+way to test it.
+
+## License
+
+In general, everything is covered by the [`LICENSE`](LICENSE) file. Some files
+specify at the top that they are covered by the
+[`LICENSE-CHROMIUM`](LICENSE-CHROMIUM) file instead.

+ 47 - 0
brightray/brightray.gyp

@@ -0,0 +1,47 @@
+{
+  'includes': [
+    'brightray.gypi',
+  ],
+  'targets': [
+    {
+      'target_name': 'brightray',
+      'type': 'static_library',
+      'include_dirs': [
+        '<(libchromiumcontent_include_dir)',
+      ],
+      'direct_dependent_settings': {
+        'include_dirs': [
+          '<(libchromiumcontent_include_dir)',
+        ],
+      },
+      'sources': [
+        'browser/browser_client.cc',
+        'browser/browser_client.h',
+        'browser/browser_context.cc',
+        'browser/browser_context.h',
+        'browser/browser_main_parts.cc',
+        'browser/browser_main_parts.h',
+        'browser/browser_main_parts_mac.mm',
+        'browser/mac/bry_application.h',
+        'browser/mac/bry_application.mm',
+        'browser/network_delegate.cc',
+        'browser/network_delegate.h',
+        'browser/url_request_context_getter.cc',
+        'browser/url_request_context_getter.h',
+        'common/main_delegate.cc',
+        'common/main_delegate.h',
+        'common/main_delegate_mac.mm',
+      ],
+      'conditions': [
+        ['OS=="mac"', {
+          'link_settings': {
+            'libraries': [
+              'libchromiumcontent.dylib',
+              '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+            ],
+          },
+        }],
+      ],
+    },
+  ],
+}

+ 39 - 0
brightray/brightray.gypi

@@ -0,0 +1,39 @@
+{
+  'variables': {
+    'libchromiumcontent_dir': 'vendor/download/libchromiumcontent',
+    'libchromiumcontent_library_dir': '<(libchromiumcontent_dir)/Release',
+    'libchromiumcontent_include_dir': '<(libchromiumcontent_dir)/include',
+    'libchromiumcontent_resources_dir': '<(libchromiumcontent_library_dir)',
+  },
+  'target_defaults': {
+    'defines': [
+      'NDEBUG',
+    ],
+    'xcode_settings': {
+      'CLANG_CXX_LANGUAGE_STANDARD': 'gnu++11',
+      'CLANG_CXX_LIBRARY': 'libstdc++',
+      'COMBINE_HIDPI_IMAGES': 'YES',
+      'GCC_ENABLE_CPP_RTTI': 'NO',
+      'GCC_TREAT_WARNINGS_AS_ERRORS': 'YES',
+      'MACOSX_DEPLOYMENT_TARGET': '10.7',
+      'RUN_CLANG_STATIC_ANALYZER': 'YES',
+      'SDKROOT': 'macosx10.7',
+      'WARNING_CFLAGS': [
+        '-Wall',
+        '-Wextra',
+        '-Wno-unused-parameter',
+        '-Wno-missing-field-initializers',
+      ],
+    },
+    'configurations': {
+      'Debug': {
+        'xcode_settings': {
+          'COPY_PHASE_STRIP': 'NO',
+          'GCC_OPTIMIZATION_LEVEL': '0',
+        },
+      },
+      'Release': {
+      },
+    },
+  },
+}

+ 35 - 0
brightray/browser/browser_client.cc

@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "browser_client.h"
+
+#include "browser_context.h"
+#include "browser_main_parts.h"
+
+namespace brightray {
+
+BrowserClient::BrowserClient() {
+}
+
+BrowserClient::~BrowserClient() {
+}
+
+BrowserContext* BrowserClient::browser_context() {
+  return browser_main_parts_->browser_context();
+}
+
+BrowserMainParts* BrowserClient::OverrideCreateBrowserMainParts(const content::MainFunctionParams&) {
+  return new BrowserMainParts;
+}
+
+content::BrowserMainParts* BrowserClient::CreateBrowserMainParts(const content::MainFunctionParams& parameters) {
+  browser_main_parts_.reset(OverrideCreateBrowserMainParts(parameters));
+  return browser_main_parts_.get();
+}
+
+net::URLRequestContextGetter* BrowserClient::CreateRequestContext(content::BrowserContext* browser_context, content::ProtocolHandlerMap* protocol_handlers) {
+  return static_cast<BrowserContext*>(browser_context)->CreateRequestContext(protocol_handlers);
+}
+
+}

+ 39 - 0
brightray/browser/browser_client.h

@@ -0,0 +1,39 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__browser_client__
+#define __brightray__browser_client__
+
+#include "content/public/browser/content_browser_client.h"
+
+namespace brightray {
+
+class BrowserContext;
+class BrowserMainParts;
+
+class BrowserClient : public content::ContentBrowserClient {
+public:
+  BrowserClient();
+  ~BrowserClient();
+
+  BrowserContext* browser_context();
+  BrowserMainParts* browser_main_parts() { return browser_main_parts_.get(); }
+
+protected:
+  // Subclasses should override this to provide their own BrowserMainParts implementation. The
+  // lifetime of the returned instance is managed by the caller.
+  virtual BrowserMainParts* OverrideCreateBrowserMainParts(const content::MainFunctionParams&);
+
+private:
+  virtual content::BrowserMainParts* CreateBrowserMainParts(const content::MainFunctionParams&) OVERRIDE;
+  virtual net::URLRequestContextGetter* CreateRequestContext(content::BrowserContext*, content::ProtocolHandlerMap*) OVERRIDE;
+
+  scoped_ptr<BrowserMainParts> browser_main_parts_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserClient);
+};
+
+}
+
+#endif /* defined(__brightray__browser_client__) */

+ 106 - 0
brightray/browser/browser_context.cc

@@ -0,0 +1,106 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "browser_context.h"
+
+#include "base/files/file_path.h"
+#include "base/path_service.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "net/base/host_resolver.h"
+#include "url_request_context_getter.h"
+
+namespace brightray {
+
+class BrowserContext::ResourceContext : public content::ResourceContext {
+public:
+  ResourceContext() : getter_(nullptr) {}
+
+  void set_url_request_context_getter(URLRequestContextGetter* getter) {
+    getter_ = getter;
+  }
+
+private:
+  virtual net::HostResolver* GetHostResolver() OVERRIDE {
+    return getter_->host_resolver();
+  }
+  
+  virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
+    return getter_->GetURLRequestContext();
+  }
+
+  URLRequestContextGetter* getter_;
+  scoped_ptr<net::HostResolver> host_resolver_;
+};
+
+BrowserContext::BrowserContext() : resource_context_(new ResourceContext) {
+}
+
+BrowserContext::~BrowserContext() {
+}
+
+net::URLRequestContextGetter* BrowserContext::CreateRequestContext(content::ProtocolHandlerMap* protocol_handlers) {
+  DCHECK(!url_request_getter_);
+  url_request_getter_.reset(new URLRequestContextGetter(
+      GetPath(),
+      content::BrowserThread::UnsafeGetMessageLoopForThread(content::BrowserThread::IO),
+      content::BrowserThread::UnsafeGetMessageLoopForThread(content::BrowserThread::FILE),
+      protocol_handlers));
+  resource_context_->set_url_request_context_getter(url_request_getter_.get());
+  return url_request_getter_.get();
+}
+
+base::FilePath BrowserContext::GetPath() {
+  // FIXME: This should be an application-specific path.
+  base::FilePath path;
+  CHECK(PathService::Get(base::DIR_APP_DATA, &path));
+  return path.Append("Brightray");
+}
+
+bool BrowserContext::IsOffTheRecord() const {
+  return false;
+}
+
+net::URLRequestContextGetter* BrowserContext::GetRequestContext() {
+  return GetDefaultStoragePartition(this)->GetURLRequestContext();
+}
+
+net::URLRequestContextGetter* BrowserContext::GetRequestContextForRenderProcess(int renderer_child_id) {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter* BrowserContext::GetMediaRequestContext() {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter* BrowserContext::GetMediaRequestContextForRenderProcess(int renderer_child_id) {
+  return GetRequestContext();
+}
+
+net::URLRequestContextGetter* BrowserContext::GetMediaRequestContextForStoragePartition(const base::FilePath& partition_path, bool in_memory) {
+  return GetRequestContext();
+}
+
+content::ResourceContext* BrowserContext::GetResourceContext() {
+  return resource_context_.get();
+}
+
+content::DownloadManagerDelegate* BrowserContext::GetDownloadManagerDelegate() {
+  return nullptr;
+}
+
+content::GeolocationPermissionContext* BrowserContext::GetGeolocationPermissionContext() {
+  return nullptr;
+}
+
+content::SpeechRecognitionPreferences* BrowserContext::GetSpeechRecognitionPreferences() {
+  return nullptr;
+}
+
+quota::SpecialStoragePolicy* BrowserContext::GetSpecialStoragePolicy() {
+  return nullptr;
+}
+
+}

+ 46 - 0
brightray/browser/browser_context.h

@@ -0,0 +1,46 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__browser_context__
+#define __brightray__browser_context__
+
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
+
+namespace brightray {
+
+class URLRequestContextGetter;
+
+class BrowserContext : public content::BrowserContext {
+public:
+  BrowserContext();
+  ~BrowserContext();
+
+  net::URLRequestContextGetter* CreateRequestContext(content::ProtocolHandlerMap*);
+
+private:
+  class ResourceContext;
+
+  virtual base::FilePath GetPath() OVERRIDE;
+  virtual bool IsOffTheRecord() const OVERRIDE;
+  virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(int renderer_child_id);
+  virtual net::URLRequestContextGetter* GetMediaRequestContext() OVERRIDE;
+  virtual net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(int renderer_child_id) OVERRIDE;
+  virtual net::URLRequestContextGetter* GetMediaRequestContextForStoragePartition(const base::FilePath& partition_path, bool in_memory);
+  virtual content::ResourceContext* GetResourceContext() OVERRIDE;
+  virtual content::DownloadManagerDelegate* GetDownloadManagerDelegate() OVERRIDE;
+  virtual content::GeolocationPermissionContext* GetGeolocationPermissionContext() OVERRIDE;
+  virtual content::SpeechRecognitionPreferences* GetSpeechRecognitionPreferences() OVERRIDE;
+  virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE;
+
+  scoped_ptr<ResourceContext> resource_context_;
+  scoped_ptr<URLRequestContextGetter> url_request_getter_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserContext);
+};
+
+}
+
+#endif /* defined(__brightray__browser_context__) */

+ 21 - 0
brightray/browser/browser_main_parts.cc

@@ -0,0 +1,21 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "browser_main_parts.h"
+
+#include "browser_context.h"
+
+namespace brightray {
+
+BrowserMainParts::BrowserMainParts() {
+}
+
+BrowserMainParts::~BrowserMainParts() {
+}
+
+void BrowserMainParts::PreMainMessageLoopRun() {
+  browser_context_.reset(new BrowserContext);
+}
+
+}

+ 38 - 0
brightray/browser/browser_main_parts.h

@@ -0,0 +1,38 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__main_parts__
+#define __brightray__main_parts__
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_main_parts.h"
+
+namespace brightray {
+
+class BrowserContext;
+
+class BrowserMainParts : public content::BrowserMainParts {
+public:
+  BrowserMainParts();
+  ~BrowserMainParts();
+
+  BrowserContext* browser_context() { return browser_context_.get(); }
+
+protected:
+#if defined(OS_MACOSX)
+  virtual void PreMainMessageLoopStart() OVERRIDE;
+#endif
+
+  virtual void PreMainMessageLoopRun() OVERRIDE;
+
+private:
+  scoped_ptr<BrowserContext> browser_context_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserMainParts);
+};
+
+}
+
+#endif /* defined(__brightray__main_parts__) */

+ 21 - 0
brightray/browser/browser_main_parts_mac.mm

@@ -0,0 +1,21 @@
+#import "browser_main_parts.h"
+
+#import "base/mac/bundle_locations.h"
+#import <AppKit/AppKit.h>
+
+namespace brightray {
+
+// Replicates NSApplicationMain, but doesn't start a run loop.
+void BrowserMainParts::PreMainMessageLoopStart() {
+  auto infoDictionary = base::mac::OuterBundle().infoDictionary;
+
+  auto principalClass = NSClassFromString([infoDictionary objectForKey:@"NSPrincipalClass"]);
+  auto application = [principalClass sharedApplication];
+
+  NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
+  auto mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:base::mac::FrameworkBundle()];
+  [mainNib instantiateNibWithOwner:application topLevelObjects:nil];
+  [mainNib release];
+}
+
+}

+ 7 - 0
brightray/browser/mac/bry_application.h

@@ -0,0 +1,7 @@
+#import "base/mac/scoped_sending_event.h"
+
+@interface BRYApplication : NSApplication <CrAppProtocol, CrAppControlProtocol> {
+  BOOL _handlingSendEvent;
+}
+
+@end

+ 19 - 0
brightray/browser/mac/bry_application.mm

@@ -0,0 +1,19 @@
+#import "bry_application.h"
+
+@interface BRYApplication ()
+
+@property (nonatomic, assign, getter = isHandlingSendEvent) BOOL handlingSendEvent;
+
+@end
+
+@implementation BRYApplication
+
+@synthesize handlingSendEvent = _handlingSendEvent;
+
+- (void)sendEvent:(NSEvent *)theEvent
+{
+  base::mac::ScopedSendingEvent scopedSendingEvent;
+  [super sendEvent:theEvent];
+}
+
+@end

+ 105 - 0
brightray/browser/network_delegate.cc

@@ -0,0 +1,105 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "network_delegate.h"
+
+#include "net/base/net_errors.h"
+
+namespace brightray {
+
+NetworkDelegate::NetworkDelegate() {
+}
+
+NetworkDelegate::~NetworkDelegate() {
+}
+
+int NetworkDelegate::OnBeforeURLRequest(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    GURL* new_url) {
+  return net::OK;
+}
+
+int NetworkDelegate::OnBeforeSendHeaders(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    net::HttpRequestHeaders* headers) {
+  return net::OK;
+}
+
+void NetworkDelegate::OnSendHeaders(
+    net::URLRequest* request,
+    const net::HttpRequestHeaders& headers) {
+}
+
+int NetworkDelegate::OnHeadersReceived(
+    net::URLRequest* request,
+    const net::CompletionCallback& callback,
+    const net::HttpResponseHeaders* original_response_headers,
+    scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
+  return net::OK;
+}
+
+void NetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
+                                            const GURL& new_location) {
+}
+
+void NetworkDelegate::OnResponseStarted(net::URLRequest* request) {
+}
+
+void NetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
+                                          int bytes_read) {
+}
+
+void NetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
+}
+
+void NetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
+}
+
+void NetworkDelegate::OnPACScriptError(int line_number,
+                                            const string16& error) {
+}
+
+NetworkDelegate::AuthRequiredResponse NetworkDelegate::OnAuthRequired(
+    net::URLRequest* request,
+    const net::AuthChallengeInfo& auth_info,
+    const AuthCallback& callback,
+    net::AuthCredentials* credentials) {
+  return AUTH_REQUIRED_RESPONSE_NO_ACTION;
+}
+
+bool NetworkDelegate::OnCanGetCookies(const net::URLRequest& request,
+                                           const net::CookieList& cookie_list) {
+  return true;
+}
+
+bool NetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
+                                          const std::string& cookie_line,
+                                          net::CookieOptions* options) {
+  return true;
+}
+
+bool NetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
+                                           const base::FilePath& path) const {
+  return true;
+}
+
+bool NetworkDelegate::OnCanThrottleRequest(
+    const net::URLRequest& request) const {
+  return false;
+}
+
+int NetworkDelegate::OnBeforeSocketStreamConnect(
+    net::SocketStream* socket,
+    const net::CompletionCallback& callback) {
+  return net::OK;
+}
+
+void NetworkDelegate::OnRequestWaitStateChange(
+    const net::URLRequest& request,
+    RequestWaitState waiting) {
+}
+
+}

+ 41 - 0
brightray/browser/network_delegate.h

@@ -0,0 +1,41 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__network_delegate__
+#define __brightray__network_delegate__
+
+#include "net/base/network_delegate.h"
+
+namespace brightray {
+
+class NetworkDelegate : public net::NetworkDelegate {
+public:
+  NetworkDelegate();
+  virtual ~NetworkDelegate();
+
+private:
+  virtual int OnBeforeURLRequest(net::URLRequest* request, const net::CompletionCallback& callback, GURL* new_url) OVERRIDE;
+  virtual int OnBeforeSendHeaders(net::URLRequest* request, const net::CompletionCallback& callback, net::HttpRequestHeaders* headers) OVERRIDE;
+  virtual void OnSendHeaders(net::URLRequest* request, const net::HttpRequestHeaders& headers) OVERRIDE;
+  virtual int OnHeadersReceived(net::URLRequest* request, const net::CompletionCallback& callback, const net::HttpResponseHeaders* original_response_headers, scoped_refptr<net::HttpResponseHeaders>* override_response_headers) OVERRIDE;
+  virtual void OnBeforeRedirect(net::URLRequest* request, const GURL& new_location) OVERRIDE;
+  virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
+  virtual void OnRawBytesRead(const net::URLRequest& request, int bytes_read) OVERRIDE;
+  virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE;
+  virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE;
+  virtual void OnPACScriptError(int line_number, const string16& error) OVERRIDE;
+  virtual AuthRequiredResponse OnAuthRequired(net::URLRequest* request, const net::AuthChallengeInfo& auth_info, const AuthCallback& callback, net::AuthCredentials* credentials) OVERRIDE;
+  virtual bool OnCanGetCookies(const net::URLRequest& request, const net::CookieList& cookie_list) OVERRIDE;
+  virtual bool OnCanSetCookie(const net::URLRequest& request, const std::string& cookie_line, net::CookieOptions* options) OVERRIDE;
+  virtual bool OnCanAccessFile(const net::URLRequest& request, const base::FilePath& path) const OVERRIDE;
+  virtual bool OnCanThrottleRequest(const net::URLRequest& request) const OVERRIDE;
+  virtual int OnBeforeSocketStreamConnect(net::SocketStream* stream, const net::CompletionCallback& callback) OVERRIDE;
+  virtual void OnRequestWaitStateChange(const net::URLRequest& request, RequestWaitState state) OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(NetworkDelegate);
+};
+
+}
+
+#endif /* defined(__brightray__network_delegate__) */

+ 137 - 0
brightray/browser/url_request_context_getter.cc

@@ -0,0 +1,137 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "url_request_context_getter.h"
+
+#include "network_delegate.h"
+#include "base/string_util.h"
+#include "base/threading/worker_pool.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/url_constants.h"
+#include "net/base/cert_verifier.h"
+#include "net/base/default_server_bound_cert_store.h"
+#include "net/base/server_bound_cert_service.h"
+#include "net/base/ssl_config_service_defaults.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/proxy/proxy_service.h"
+#include "net/url_request/static_http_user_agent_settings.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_storage.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+
+namespace brightray {
+
+URLRequestContextGetter::URLRequestContextGetter(
+    const base::FilePath& base_path,
+    MessageLoop* io_loop,
+    MessageLoop* file_loop,
+    content::ProtocolHandlerMap* protocol_handlers)
+    : base_path_(base_path),
+      io_loop_(io_loop),
+      file_loop_(file_loop) {
+  // Must first be created on the UI thread.
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+  std::swap(protocol_handlers_, *protocol_handlers);
+
+  proxy_config_service_.reset(net::ProxyService::CreateSystemProxyConfigService(io_loop_->message_loop_proxy(), file_loop_));
+}
+
+URLRequestContextGetter::~URLRequestContextGetter() {
+}
+
+net::HostResolver* URLRequestContextGetter::host_resolver() {
+  return url_request_context_->host_resolver();
+}
+
+net::URLRequestContext* URLRequestContextGetter::GetURLRequestContext()
+{
+  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+
+  if (!url_request_context_.get()) {
+    url_request_context_.reset(new net::URLRequestContext());
+    network_delegate_.reset(new NetworkDelegate);
+    url_request_context_->set_network_delegate(network_delegate_.get());
+    storage_.reset(
+        new net::URLRequestContextStorage(url_request_context_.get()));
+    storage_->set_cookie_store(new net::CookieMonster(NULL, NULL));
+    storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
+        new net::DefaultServerBoundCertStore(NULL),
+        base::WorkerPool::GetTaskRunner(true)));
+    storage_->set_http_user_agent_settings(
+        new net::StaticHttpUserAgentSettings(
+            "en-us,en", "iso-8859-1,*,utf-8", EmptyString()));
+
+    scoped_ptr<net::HostResolver> host_resolver(
+        net::HostResolver::CreateDefaultResolver(NULL));
+
+    storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
+    // TODO(jam): use v8 if possible, look at chrome code.
+    storage_->set_proxy_service(
+        net::ProxyService::CreateUsingSystemProxyResolver(
+        proxy_config_service_.release(),
+        0,
+        NULL));
+    storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
+    storage_->set_http_auth_handler_factory(
+        net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
+    storage_->set_http_server_properties(new net::HttpServerPropertiesImpl);
+
+    base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
+    net::HttpCache::DefaultBackend* main_backend =
+        new net::HttpCache::DefaultBackend(
+            net::DISK_CACHE,
+            cache_path,
+            0,
+            content::BrowserThread::GetMessageLoopProxyForThread(
+                content::BrowserThread::CACHE));
+
+    net::HttpNetworkSession::Params network_session_params;
+    network_session_params.cert_verifier =
+        url_request_context_->cert_verifier();
+    network_session_params.server_bound_cert_service =
+        url_request_context_->server_bound_cert_service();
+    network_session_params.proxy_service =
+        url_request_context_->proxy_service();
+    network_session_params.ssl_config_service =
+        url_request_context_->ssl_config_service();
+    network_session_params.http_auth_handler_factory =
+        url_request_context_->http_auth_handler_factory();
+    network_session_params.network_delegate =
+        url_request_context_->network_delegate();
+    network_session_params.http_server_properties =
+        url_request_context_->http_server_properties();
+    network_session_params.ignore_certificate_errors = false;
+
+    // Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
+    storage_->set_host_resolver(host_resolver.Pass());
+    network_session_params.host_resolver =
+        url_request_context_->host_resolver();
+
+    net::HttpCache* main_cache = new net::HttpCache(
+        network_session_params, main_backend);
+    storage_->set_http_transaction_factory(main_cache);
+
+    scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
+        new net::URLRequestJobFactoryImpl());
+    for (auto& it : protocol_handlers_) {
+      bool set_protocol = job_factory->SetProtocolHandler(it.first, it.second.release());
+      DCHECK(set_protocol);
+    }
+    protocol_handlers_.clear();
+    storage_->set_job_factory(job_factory.release());
+  }
+
+  return url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetter::GetNetworkTaskRunner() const
+{
+  return content::BrowserThread::GetMessageLoopProxyForThread(content::BrowserThread::IO);
+}
+
+}

+ 54 - 0
brightray/browser/url_request_context_getter.h

@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__url_request_context_getter__
+#define __brightray__url_request_context_getter__
+
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/content_browser_client.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class MessageLoop;
+
+namespace net {
+class HostResolver;
+class NetworkDelegate;
+class ProxyConfigService;
+class URLRequestContextStorage;
+}
+
+namespace brightray {
+
+class URLRequestContextGetter : public net::URLRequestContextGetter {
+public:
+  URLRequestContextGetter(
+      const base::FilePath& base_path,
+      MessageLoop* io_loop,
+      MessageLoop* file_loop,
+      content::ProtocolHandlerMap*);
+  virtual ~URLRequestContextGetter();
+
+  net::HostResolver* host_resolver();
+  virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
+
+private:
+  virtual scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const OVERRIDE;
+
+  base::FilePath base_path_;
+  MessageLoop* io_loop_;
+  MessageLoop* file_loop_;
+
+  scoped_ptr<net::ProxyConfigService> proxy_config_service_;
+  scoped_ptr<net::NetworkDelegate> network_delegate_;
+  scoped_ptr<net::URLRequestContextStorage> storage_;
+  scoped_ptr<net::URLRequestContext> url_request_context_;
+  content::ProtocolHandlerMap protocol_handlers_;
+
+  DISALLOW_COPY_AND_ASSIGN(URLRequestContextGetter);
+};
+
+}
+
+#endif /* defined(__brightray__url_request_context_getter__) */

+ 29 - 0
brightray/common/main_delegate.cc

@@ -0,0 +1,29 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#include "main_delegate.h"
+
+#include "browser_client.h"
+#include "base/command_line.h"
+#include "content/public/common/content_switches.h"
+
+namespace brightray {
+
+MainDelegate::MainDelegate() {
+}
+
+MainDelegate::~MainDelegate() {
+}
+
+void MainDelegate::PreSandboxStartup() {
+  // FIXME: We don't currently support running sandboxed.
+  CommandLine::ForCurrentProcess()->AppendSwitch(switches::kNoSandbox);
+
+#if defined(OS_MACOSX)
+  OverrideChildProcessPath();
+  OverrideFrameworkBundlePath();
+#endif
+}
+
+}

+ 31 - 0
brightray/common/main_delegate.h

@@ -0,0 +1,31 @@
+// Copyright (c) 2012 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-CHROMIUM file.
+
+#ifndef __brightray__main_delegate__
+#define __brightray__main_delegate__
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/app/content_main_delegate.h"
+
+namespace brightray {
+
+class MainDelegate : public content::ContentMainDelegate {
+public:
+  MainDelegate();
+  ~MainDelegate();
+
+private:
+#if defined(OS_MACOSX)
+  static void OverrideChildProcessPath();
+  static void OverrideFrameworkBundlePath();
+#endif
+
+  virtual void PreSandboxStartup() OVERRIDE;
+
+  DISALLOW_COPY_AND_ASSIGN(MainDelegate);
+};
+
+}
+#endif /* defined(__brightray__main_delegate__) */

+ 59 - 0
brightray/common/main_delegate_mac.mm

@@ -0,0 +1,59 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2013 Adam Roben <[email protected]>. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE-CHROMIUM file.
+
+#import "main_delegate.h"
+
+#include "base/mac/bundle_locations.h"
+#include "base/mac/foundation_util.h"
+#include "base/path_service.h"
+#include "content/public/common/content_paths.h"
+
+namespace brightray {
+
+namespace {
+
+base::FilePath GetFrameworksPath() {
+  // Start out with the path to the running executable.
+  base::FilePath path;
+  PathService::Get(base::FILE_EXE, &path);
+  
+  // Up to Contents.
+  if (base::mac::IsBackgroundOnlyProcess()) {
+    // The running executable is the helper. Go up five steps:
+    // Contents/Frameworks/Helper.app/Contents/MacOS/Helper
+    // ^ to here                                     ^ from here
+    path = path.DirName().DirName().DirName().DirName().DirName();
+  } else {
+    // One step up to MacOS, another to Contents.
+    path = path.DirName().DirName();
+  }
+  DCHECK_EQ(path.BaseName().value(), "Contents");
+  
+  // Go into the frameworks directory.
+  return path.Append("Frameworks");
+}
+
+std::string OuterBundleName() {
+  return [[base::mac::OuterBundle().infoDictionary objectForKey:base::mac::CFToNSCast(kCFBundleNameKey)] UTF8String];
+}
+
+}
+
+void MainDelegate::OverrideFrameworkBundlePath() {
+  base::FilePath helper_path = GetFrameworksPath().Append(OuterBundleName() + ".framework");
+
+  base::mac::SetOverrideFrameworkBundlePath(helper_path);
+}
+
+void MainDelegate::OverrideChildProcessPath() {
+  base::FilePath helper_path = GetFrameworksPath().Append(OuterBundleName() + " Helper.app")
+    .Append("Contents")
+    .Append("MacOS")
+    .Append(OuterBundleName() + " Helper");
+
+  PathService::Override(content::CHILD_PROCESS_EXE, helper_path);
+}
+
+}

+ 26 - 0
brightray/script/bootstrap

@@ -0,0 +1,26 @@
+#!/bin/sh
+#/ Usage: bootstrap https://base.url.com/from/libchromiumcontent/script/upload
+#/ Bootstrap this project.
+
+set -e
+
+usage() {
+  grep '^#/' <"$0"| cut -c4-
+}
+
+BASE_URL="${1}"
+
+if [ -z "${BASE_URL}" ]; then
+  usage
+  exit 1
+fi
+
+cd "$(dirname "$0")/.."
+
+git submodule sync --quiet
+git submodule update --init --recursive
+
+SOURCE_ROOT="$(pwd -P)"
+DOWNLOAD_DIR="${SOURCE_ROOT}/vendor/download"
+mkdir -p "${DOWNLOAD_DIR}"
+vendor/libchromiumcontent/script/download "${BASE_URL}" "${DOWNLOAD_DIR}/libchromiumcontent"

+ 8 - 0
brightray/script/build

@@ -0,0 +1,8 @@
+#!/bin/sh
+
+set -e
+
+cd "$(dirname "$0")/.."
+
+gyp --depth . brightray.gyp
+xcodebuild

+ 273 - 0
brightray/tools/mac/change_mach_o_flags.py

@@ -0,0 +1,273 @@
+#!/usr/bin/env python
+# Copyright (c) 2011 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-CHROMIUM file.
+
+"""Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executablepath>
+
+Arranges for the executable at |executable_path| to have its data (heap)
+pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
+the PIE (position independent executable) bit set to enable ASLR (address
+space layout randomization). With --executable-heap or --no-pie, the
+respective bits are cleared instead of set, making the heap executable or
+disabling PIE/ASLR.
+
+This script is able to operate on thin (single-architecture) Mach-O files
+and fat (universal, multi-architecture) files. When operating on fat files,
+it will set or clear the bits for each architecture contained therein.
+
+NON-EXECUTABLE HEAP
+
+Traditionally in Mac OS X, 32-bit processes did not have data pages set to
+prohibit execution. Although user programs could call mprotect and
+mach_vm_protect to deny execution of code in data pages, the kernel would
+silently ignore such requests without updating the page tables, and the
+hardware would happily execute code on such pages. 64-bit processes were
+always given proper hardware protection of data pages. This behavior was
+controllable on a system-wide level via the vm.allow_data_exec sysctl, which
+is set by default to 1. The bit with value 1 (set by default) allows code
+execution on data pages for 32-bit processes, and the bit with value 2
+(clear by default) does the same for 64-bit processes.
+
+In Mac OS X 10.7, executables can "opt in" to having hardware protection
+against code execution on data pages applied. This is done by setting a new
+bit in the |flags| field of an executable's |mach_header|. When
+MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless
+of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c
+override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile.
+
+The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when
+producing executables, provided that -allow_heap_execute is not specified
+at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and
+later) have this ability. See ld64-123.2.1/src/ld/Options.cpp
+Options::reconfigureDefaults() and
+ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp
+HeaderAndLoadCommandsAtom<A>::flags().
+
+This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is
+intended for use with executables produced by a linker that predates Apple's
+modifications to set this bit itself. It is also useful for setting this bit
+for non-i386 executables, including x86_64 executables. Apple's linker only
+sets it for 32-bit i386 executables, presumably under the assumption that
+the value of vm.allow_data_exec is set in stone. However, if someone were to
+change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run
+without hardware protection against code execution on data pages. This
+script can set the bit for x86_64 executables, guaranteeing that they run
+with appropriate protection even when vm.allow_data_exec has been tampered
+with.
+
+POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
+
+This script sets or clears the MH_PIE bit in an executable's Mach-O header,
+enabling or disabling position independence on Mac OS X 10.5 and later.
+Processes running position-independent executables have varying levels of
+ASLR protection depending on the OS release. The main executable's load
+address, shared library load addresess, and the heap and stack base
+addresses may be randomized. Position-independent executables are produced
+by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
+Executables linked with a deployment target of 10.7 or higher have PIE on
+by default.
+
+This script is never strictly needed during the build to enable PIE, as all
+linkers used are recent enough to support -pie. However, it's used to
+disable the PIE bit as needed on already-linked executables.
+"""
+
+import optparse
+import os
+import struct
+import sys
+
+
+# <mach-o/fat.h>
+FAT_MAGIC = 0xcafebabe
+FAT_CIGAM = 0xbebafeca
+
+# <mach-o/loader.h>
+MH_MAGIC = 0xfeedface
+MH_CIGAM = 0xcefaedfe
+MH_MAGIC_64 = 0xfeedfacf
+MH_CIGAM_64 = 0xcffaedfe
+MH_EXECUTE = 0x2
+MH_PIE = 0x00200000
+MH_NO_HEAP_EXECUTION = 0x01000000
+
+
+class MachOError(Exception):
+  """A class for exceptions thrown by this module."""
+
+  pass
+
+
+def CheckedSeek(file, offset):
+  """Seeks the file-like object at |file| to offset |offset| and raises a
+  MachOError if anything funny happens."""
+
+  file.seek(offset, os.SEEK_SET)
+  new_offset = file.tell()
+  if new_offset != offset:
+    raise MachOError, \
+          'seek: expected offset %d, observed %d' % (offset, new_offset)
+
+
+def CheckedRead(file, count):
+  """Reads |count| bytes from the file-like |file| object, raising a
+  MachOError if any other number of bytes is read."""
+
+  bytes = file.read(count)
+  if len(bytes) != count:
+    raise MachOError, \
+          'read: expected length %d, observed %d' % (count, len(bytes))
+
+  return bytes
+
+
+def ReadUInt32(file, endian):
+  """Reads an unsinged 32-bit integer from the file-like |file| object,
+  treating it as having endianness specified by |endian| (per the |struct|
+  module), and returns it as a number. Raises a MachOError if the proper
+  length of data can't be read from |file|."""
+
+  bytes = CheckedRead(file, 4)
+
+  (uint32,) = struct.unpack(endian + 'I', bytes)
+  return uint32
+
+
+def ReadMachHeader(file, endian):
+  """Reads an entire |mach_header| structure (<mach-o/loader.h>) from the
+  file-like |file| object, treating it as having endianness specified by
+  |endian| (per the |struct| module), and returns a 7-tuple of its members
+  as numbers. Raises a MachOError if the proper length of data can't be read
+  from |file|."""
+
+  bytes = CheckedRead(file, 28)
+
+  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
+      struct.unpack(endian + '7I', bytes)
+  return magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags
+
+
+def ReadFatArch(file):
+  """Reads an entire |fat_arch| structure (<mach-o/fat.h>) from the file-like
+  |file| object, treating it as having endianness specified by |endian|
+  (per the |struct| module), and returns a 5-tuple of its members as numbers.
+  Raises a MachOError if the proper length of data can't be read from
+  |file|."""
+
+  bytes = CheckedRead(file, 20)
+
+  cputype, cpusubtype, offset, size, align = struct.unpack('>5I', bytes)
+  return cputype, cpusubtype, offset, size, align
+
+
+def WriteUInt32(file, uint32, endian):
+  """Writes |uint32| as an unsinged 32-bit integer to the file-like |file|
+  object, treating it as having endianness specified by |endian| (per the
+  |struct| module)."""
+
+  bytes = struct.pack(endian + 'I', uint32)
+  assert len(bytes) == 4
+
+  file.write(bytes)
+
+
+def HandleMachOFile(file, options, offset=0):
+  """Seeks the file-like |file| object to |offset|, reads its |mach_header|,
+  and rewrites the header's |flags| field if appropriate. The header's
+  endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
+  (mach_header and mach_header_64). Raises MachOError if used on a header that
+  does not have a known magic number or is not of type MH_EXECUTE. The
+  MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
+  according to |options| and written to |file| if any changes need to be made.
+  If already set or clear as specified by |options|, nothing is written."""
+
+  CheckedSeek(file, offset)
+  magic = ReadUInt32(file, '<')
+  if magic == MH_MAGIC or magic == MH_MAGIC_64:
+    endian = '<'
+  elif magic == MH_CIGAM or magic == MH_CIGAM_64:
+    endian = '>'
+  else:
+    raise MachOError, \
+          'Mach-O file at offset %d has illusion of magic' % offset
+
+  CheckedSeek(file, offset)
+  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
+      ReadMachHeader(file, endian)
+  assert magic == MH_MAGIC or magic == MH_MAGIC_64
+  if filetype != MH_EXECUTE:
+    raise MachOError, \
+          'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
+              (offset, filetype)
+
+  original_flags = flags
+
+  if options.no_heap_execution:
+    flags |= MH_NO_HEAP_EXECUTION
+  else:
+    flags &= ~MH_NO_HEAP_EXECUTION
+
+  if options.pie:
+    flags |= MH_PIE
+  else:
+    flags &= ~MH_PIE
+
+  if flags != original_flags:
+    CheckedSeek(file, offset + 24)
+    WriteUInt32(file, flags, endian)
+
+
+def HandleFatFile(file, options, fat_offset=0):
+  """Seeks the file-like |file| object to |offset| and loops over its
+  |fat_header| entries, calling HandleMachOFile for each."""
+
+  CheckedSeek(file, fat_offset)
+  magic = ReadUInt32(file, '>')
+  assert magic == FAT_MAGIC
+
+  nfat_arch = ReadUInt32(file, '>')
+
+  for index in xrange(0, nfat_arch):
+    cputype, cpusubtype, offset, size, align = ReadFatArch(file)
+    assert size >= 28
+
+    # HandleMachOFile will seek around. Come back here after calling it, in
+    # case it sought.
+    fat_arch_offset = file.tell()
+    HandleMachOFile(file, options, offset)
+    CheckedSeek(file, fat_arch_offset)
+
+
+def main(me, args):
+  parser = optparse.OptionParser('%prog [options] <executable_path>')
+  parser.add_option('--executable-heap', action='store_false',
+                    dest='no_heap_execution', default=True,
+                    help='Clear the MH_NO_HEAP_EXECUTION bit')
+  parser.add_option('--no-pie', action='store_false',
+                    dest='pie', default=True,
+                    help='Clear the MH_PIE bit')
+  (options, loose_args) = parser.parse_args(args)
+  if len(loose_args) != 1:
+    parser.print_usage()
+    return 1
+
+  executable_path = loose_args[0]
+  executable_file = open(executable_path, 'rb+')
+
+  magic = ReadUInt32(executable_file, '<')
+  if magic == FAT_CIGAM:
+    # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
+    HandleFatFile(executable_file, options)
+  elif magic == MH_MAGIC or magic == MH_CIGAM or \
+      magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
+    HandleMachOFile(executable_file, options)
+  else:
+    raise MachOError, '%s is not a Mach-O or fat file' % executable_file
+
+  executable_file.close()
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[0], sys.argv[1:]))

+ 91 - 0
brightray/tools/mac/make_more_helpers.sh

@@ -0,0 +1,91 @@
+#!/bin/bash
+
+# Copyright (c) 2012 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-CHROMIUM file.
+
+# Usage: make_more_helpers.sh <directory_within_contents> <app_name>
+#
+# This script creates additional helper .app bundles for Chromium, based on
+# the existing helper .app bundle, changing their Mach-O header's flags to
+# enable and disable various features. Based on Chromium Helper.app, it will
+# create Chromium Helper EH.app, which has the MH_NO_HEAP_EXECUTION bit
+# cleared to support Chromium child processes that require an executable heap,
+# and Chromium Helper NP.app, which has the MH_PIE bit cleared to support
+# Chromium child processes that cannot tolerate ASLR.
+#
+# This script expects to be called from the chrome_exe target as a postbuild,
+# and operates directly within the built-up browser app's versioned directory.
+#
+# Each helper is adjusted by giving it the proper bundle name, renaming the
+# executable, adjusting several Info.plist keys, and changing the executable's
+# Mach-O flags.
+
+set -eu
+
+make_helper() {
+  local containing_dir="${1}"
+  local app_name="${2}"
+  local feature="${3}"
+  local flags="${4}"
+
+  local helper_name="${app_name} Helper"
+  local helper_stem="${containing_dir}/${helper_name}"
+  local original_helper="${helper_stem}.app"
+  if [[ ! -d "${original_helper}" ]]; then
+    echo "${0}: error: ${original_helper} is a required directory" >& 2
+    exit 1
+  fi
+  local original_helper_exe="${original_helper}/Contents/MacOS/${helper_name}"
+  if [[ ! -f "${original_helper_exe}" ]]; then
+    echo "${0}: error: ${original_helper_exe} is a required file" >& 2
+    exit 1
+  fi
+
+  local feature_helper="${helper_stem} ${feature}.app"
+
+  rsync -acC --delete --include '*.so' "${original_helper}/" "${feature_helper}"
+
+  local helper_feature="${helper_name} ${feature}"
+  local helper_feature_exe="${feature_helper}/Contents/MacOS/${helper_feature}"
+  mv "${feature_helper}/Contents/MacOS/${helper_name}" "${helper_feature_exe}"
+
+  local change_flags="$(dirname "${0}")/change_mach_o_flags.py"
+  "${change_flags}" ${flags} "${helper_feature_exe}"
+
+  local feature_info="${feature_helper}/Contents/Info"
+  local feature_info_plist="${feature_info}.plist"
+
+  defaults write "${feature_info}" "CFBundleDisplayName" "${helper_feature}"
+  defaults write "${feature_info}" "CFBundleExecutable" "${helper_feature}"
+
+  cfbundleid="$(defaults read "${feature_info}" "CFBundleIdentifier")"
+  feature_cfbundleid="${cfbundleid}.${feature}"
+  defaults write "${feature_info}" "CFBundleIdentifier" "${feature_cfbundleid}"
+
+  cfbundlename="$(defaults read "${feature_info}" "CFBundleName")"
+  feature_cfbundlename="${cfbundlename} ${feature}"
+  defaults write "${feature_info}" "CFBundleName" "${feature_cfbundlename}"
+
+  # As usual, defaults might have put the plist into whatever format excites
+  # it, but Info.plists get converted back to the expected XML format.
+  plutil -convert xml1 "${feature_info_plist}"
+
+  # `defaults` also changes the file permissions, so make the file
+  # world-readable again.
+  chmod a+r "${feature_info_plist}"
+}
+
+if [[ ${#} -ne 2 ]]; then
+  echo "usage: ${0} <directory_within_contents> <app_name>" >& 2
+  exit 1
+fi
+
+DIRECTORY_WITHIN_CONTENTS="${1}"
+APP_NAME="${2}"
+
+CONTENTS_DIR="${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}"
+CONTAINING_DIR="${CONTENTS_DIR}/${DIRECTORY_WITHIN_CONTENTS}"
+
+make_helper "${CONTAINING_DIR}" "${APP_NAME}" "EH" "--executable-heap"
+make_helper "${CONTAINING_DIR}" "${APP_NAME}" "NP" "--no-pie"

+ 1 - 0
brightray/vendor/.gitignore

@@ -0,0 +1 @@
+/download/

+ 1 - 0
brightray/vendor/libchromiumcontent

@@ -0,0 +1 @@
+Subproject commit 3f6f01c46be61f36b4e25456bf2c0539ef4d77f3