Don't pass a null ServiceWorker registration with OK status code.
[chromium-blink-merge.git] / content / renderer / renderer_main_platform_delegate_mac.mm
blob7c42727ad32b3661c81a5411657622d9ca17748e
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/renderer_main_platform_delegate.h"
7 #include <Carbon/Carbon.h>
8 #import <Cocoa/Cocoa.h>
9 #include <objc/runtime.h>
11 #include "base/command_line.h"
12 #include "base/logging.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "content/common/sandbox_mac.h"
17 #include "content/public/common/content_switches.h"
18 #import "content/public/common/injection_test_mac.h"
19 #include "content/common/sandbox_init_mac.h"
21 namespace content {
23 namespace {
25 // You are about to read a pretty disgusting hack. In a static initializer,
26 // CoreFoundation decides to connect with cfprefsd(8) using Mach IPC. There is
27 // no public way to close this Mach port after-the-fact, nor a way to stop it
28 // from happening since it is done pre-main in dyld. But the address of the
29 // CFMachPort can be found in the run loop's string description. Below, that
30 // address is parsed, cast, and then used to invalidate the Mach port to
31 // disable communication with cfprefsd.
32 void DisconnectCFNotificationCenter() {
33   base::ScopedCFTypeRef<CFStringRef> run_loop_description(
34       CFCopyDescription(CFRunLoopGetCurrent()));
35   const CFIndex length = CFStringGetLength(run_loop_description);
36   for (CFIndex i = 0; i < length; ) {
37     // Find the start of a CFMachPort run loop source, which looks like this,
38     // without new lines:
39     // 1 : <CFRunLoopSource 0x7d16ea90 [0xa160af80]>{signalled = No,
40     // valid = Yes, order = 0, context =
41     // <CFMachPort 0x7d16fe00 [0xa160af80]>{valid = Yes, port = 3a0f,
42     // source = 0x7d16ea90, callout =
43     // _ZL14MessageHandlerP12__CFMachPortPvlS1_ (0x96df59c2), context =
44     // <CFMachPort context 0x1475b>}}
45     CFRange run_loop_source_context_range;
46     if (!CFStringFindWithOptions(run_loop_description,
47             CFSTR(", context = <CFMachPort "), CFRangeMake(i, length - i),
48             0, &run_loop_source_context_range)) {
49       break;
50     }
51     i = run_loop_source_context_range.location +
52         run_loop_source_context_range.length;
54     // The address of the CFMachPort is the first hexadecimal address after the
55     // CF type name.
56     CFRange port_address_range = CFRangeMake(i, 0);
57     for (CFIndex j = port_address_range.location; j < length; ++j) {
58       UniChar c = CFStringGetCharacterAtIndex(run_loop_description, j);
59       if (c == ' ')
60         break;
61       ++port_address_range.length;
62     }
64     base::ScopedCFTypeRef<CFStringRef> port_address_string(
65         CFStringCreateWithSubstring(NULL, run_loop_description,
66             port_address_range));
67     if (!port_address_string)
68       continue;
70     // Convert the string to an address.
71     std::string port_address_std_string =
72         base::SysCFStringRefToUTF8(port_address_string);
73 #if __LP64__
74     uint64 port_address = 0;
75     if (!base::HexStringToUInt64(port_address_std_string, &port_address))
76       continue;
77 #else
78     uint32 port_address = 0;
79     if (!base::HexStringToUInt(port_address_std_string, &port_address))
80       continue;
81 #endif
83     // Cast the address to an object.
84     CFMachPortRef mach_port = reinterpret_cast<CFMachPortRef>(port_address);
85     if (CFGetTypeID(mach_port) != CFMachPortGetTypeID())
86       continue;
88     // Verify that this is the Mach port that needs to be disconnected by the
89     // name of its callout function. Example description (no new lines):
90     // <CFMachPort 0x7d16fe00 [0xa160af80]>{valid = Yes, port = 3a0f, source =
91     // 0x7d16ea90, callout = __CFXNotificationReceiveFromServer (0x96df59c2),
92     // context = <CFMachPort context 0x1475b>}
93     base::ScopedCFTypeRef<CFStringRef> port_description(
94         CFCopyDescription(mach_port));
95     if (CFStringFindWithOptions(port_description,
96             CFSTR(", callout = __CFXNotificationReceiveFromServer ("),
97             CFRangeMake(0, CFStringGetLength(port_description)),
98             0,
99             NULL)) {
100       CFMachPortInvalidate(mach_port);
101       return;
102     }
103   }
106 }  // namespace
108 RendererMainPlatformDelegate::RendererMainPlatformDelegate(
109     const MainFunctionParams& parameters)
110         : parameters_(parameters) {
113 RendererMainPlatformDelegate::~RendererMainPlatformDelegate() {
116 // TODO(mac-port): Any code needed to initialize a process for purposes of
117 // running a renderer needs to also be reflected in chrome_main.cc for
118 // --single-process support.
119 void RendererMainPlatformDelegate::PlatformInitialize() {
120   if (![NSThread isMultiThreaded]) {
121     NSString* string = @"";
122     [NSThread detachNewThreadSelector:@selector(length)
123                              toTarget:string
124                            withObject:nil];
125   }
128 void RendererMainPlatformDelegate::PlatformUninitialize() {
131 static void LogTestMessage(std::string message, bool is_error) {
132   if (is_error)
133     LOG(ERROR) << message;
134   else
135     VLOG(0) << message;
138 bool RendererMainPlatformDelegate::InitSandboxTests(bool no_sandbox) {
139   const CommandLine& command_line = parameters_.command_line;
141   if (command_line.HasSwitch(switches::kTestSandbox)) {
142     std::string bundle_path =
143     command_line.GetSwitchValueNative(switches::kTestSandbox);
144     if (bundle_path.empty()) {
145       NOTREACHED() << "Bad bundle path";
146       return false;
147     }
148     NSBundle* tests_bundle =
149         [NSBundle bundleWithPath:base::SysUTF8ToNSString(bundle_path)];
150     if (![tests_bundle load]) {
151       NOTREACHED() << "Failed to load bundle";
152       return false;
153     }
154     sandbox_tests_bundle_ = [tests_bundle retain];
155     [objc_getClass("RendererSandboxTestsRunner") setLogFunction:LogTestMessage];
156   }
157   return true;
160 bool RendererMainPlatformDelegate::EnableSandbox() {
161   // Enable the sandbox.
162   bool sandbox_initialized = InitializeSandbox();
164   // The sandbox is now engaged. Make sure that the renderer has not connected
165   // itself to Cocoa.
166   CHECK(NSApp == nil);
168   DisconnectCFNotificationCenter();
170   return sandbox_initialized;
173 void RendererMainPlatformDelegate::RunSandboxTests(bool no_sandbox) {
174   Class tests_runner = objc_getClass("RendererSandboxTestsRunner");
175   if (tests_runner) {
176     if (![tests_runner runTests])
177       LOG(ERROR) << "Running renderer with failing sandbox tests!";
178     [sandbox_tests_bundle_ unload];
179     [sandbox_tests_bundle_ release];
180     sandbox_tests_bundle_ = nil;
181   }
184 }  // namespace content