Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 //
2 // GTMLogger.m
3 //
4 // Copyright 2007-2008 Google Inc.
5 //
6 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
7 // use this file except in compliance with the License. You may obtain a copy
8 // of the License at
9 //
10 // http://www.apache.org/licenses/LICENSE-2.0
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 // License for the specific language governing permissions and limitations under
16 // the License.
17 //
19 #import "GTMLogger.h"
20 #import "GTMGarbageCollection.h"
21 #import <fcntl.h>
22 #import <unistd.h>
23 #import <stdlib.h>
24 #import <pthread.h>
27 #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
28 // Some versions of GCC (4.2 and below AFAIK) aren't great about supporting
29 // -Wmissing-format-attribute
30 // when the function is anything more complex than foo(NSString *fmt, ...).
31 // You see the error inside the function when you turn ... into va_args and
32 // attempt to call another function (like vsprintf for example).
33 // So we just shut off the warning for this file. We reenable it at the end.
34 #pragma GCC diagnostic ignored "-Wmissing-format-attribute"
35 #endif // !__clang__
37 // Reference to the shared GTMLogger instance. This is not a singleton, it's
38 // just an easy reference to one shared instance.
39 static GTMLogger *gSharedLogger = nil;
42 @implementation GTMLogger
44 // Returns a pointer to the shared logger instance. If none exists, a standard
45 // logger is created and returned.
46 + (id)sharedLogger {
47 @synchronized(self) {
48 if (gSharedLogger == nil) {
49 gSharedLogger = [[self standardLogger] retain];
50 }
51 }
52 return [[gSharedLogger retain] autorelease];
53 }
55 + (void)setSharedLogger:(GTMLogger *)logger {
56 @synchronized(self) {
57 [gSharedLogger autorelease];
58 gSharedLogger = [logger retain];
59 }
60 }
62 + (id)standardLogger {
63 // Don't trust NSFileHandle not to throw
64 @try {
65 id<GTMLogWriter> writer = [NSFileHandle fileHandleWithStandardOutput];
66 id<GTMLogFormatter> fr = [[[GTMLogStandardFormatter alloc] init]
67 autorelease];
68 id<GTMLogFilter> filter = [[[GTMLogLevelFilter alloc] init] autorelease];
69 return [[[self alloc] initWithWriter:writer
70 formatter:fr
71 filter:filter] autorelease];
72 }
73 @catch (id e) {
74 // Ignored
75 }
76 return nil;
77 }
79 + (id)standardLoggerWithStderr {
80 // Don't trust NSFileHandle not to throw
81 @try {
82 id me = [self standardLogger];
83 [me setWriter:[NSFileHandle fileHandleWithStandardError]];
84 return me;
85 }
86 @catch (id e) {
87 // Ignored
88 }
89 return nil;
90 }
92 + (id)standardLoggerWithStdoutAndStderr {
93 // We're going to take advantage of the GTMLogger to GTMLogWriter adaptor
94 // and create a composite logger that an outer "standard" logger can use
95 // as a writer. Our inner loggers should apply no formatting since the main
96 // logger does that and we want the caller to be able to change formatters
97 // or add writers without knowing the inner structure of our composite.
99 // Don't trust NSFileHandle not to throw
100 @try {
101 GTMLogBasicFormatter *formatter = [[[GTMLogBasicFormatter alloc] init]
102 autorelease];
103 GTMLogger *stdoutLogger =
104 [self loggerWithWriter:[NSFileHandle fileHandleWithStandardOutput]
105 formatter:formatter
106 filter:[[[GTMLogMaximumLevelFilter alloc]
107 initWithMaximumLevel:kGTMLoggerLevelInfo]
108 autorelease]];
109 GTMLogger *stderrLogger =
110 [self loggerWithWriter:[NSFileHandle fileHandleWithStandardError]
111 formatter:formatter
112 filter:[[[GTMLogMininumLevelFilter alloc]
113 initWithMinimumLevel:kGTMLoggerLevelError]
114 autorelease]];
115 GTMLogger *compositeWriter =
116 [self loggerWithWriter:[NSArray arrayWithObjects:
117 stdoutLogger, stderrLogger, nil]
118 formatter:formatter
119 filter:[[[GTMLogNoFilter alloc] init] autorelease]];
120 GTMLogger *outerLogger = [self standardLogger];
121 [outerLogger setWriter:compositeWriter];
122 return outerLogger;
123 }
124 @catch (id e) {
125 // Ignored
126 }
127 return nil;
128 }
130 + (id)standardLoggerWithPath:(NSString *)path {
131 @try {
132 NSFileHandle *fh = [NSFileHandle fileHandleForLoggingAtPath:path mode:0644];
133 if (fh == nil) return nil;
134 id me = [self standardLogger];
135 [me setWriter:fh];
136 return me;
137 }
138 @catch (id e) {
139 // Ignored
140 }
141 return nil;
142 }
144 + (id)loggerWithWriter:(id<GTMLogWriter>)writer
145 formatter:(id<GTMLogFormatter>)formatter
146 filter:(id<GTMLogFilter>)filter {
147 return [[[self alloc] initWithWriter:writer
148 formatter:formatter
149 filter:filter] autorelease];
150 }
152 + (id)logger {
153 return [[[self alloc] init] autorelease];
154 }
156 - (id)init {
157 return [self initWithWriter:nil formatter:nil filter:nil];
158 }
160 - (id)initWithWriter:(id<GTMLogWriter>)writer
161 formatter:(id<GTMLogFormatter>)formatter
162 filter:(id<GTMLogFilter>)filter {
163 if ((self = [super init])) {
164 [self setWriter:writer];
165 [self setFormatter:formatter];
166 [self setFilter:filter];
167 }
168 return self;
169 }
171 - (void)dealloc {
172 // Unlikely, but |writer_| may be an NSFileHandle, which can throw
173 @try {
174 [formatter_ release];
175 [filter_ release];
176 [writer_ release];
177 }
178 @catch (id e) {
179 // Ignored
180 }
181 [super dealloc];
182 }
184 - (id<GTMLogWriter>)writer {
185 return [[writer_ retain] autorelease];
186 }
188 - (void)setWriter:(id<GTMLogWriter>)writer {
189 @synchronized(self) {
190 [writer_ autorelease];
191 writer_ = nil;
192 if (writer == nil) {
193 // Try to use stdout, but don't trust NSFileHandle
194 @try {
195 writer_ = [[NSFileHandle fileHandleWithStandardOutput] retain];
196 }
197 @catch (id e) {
198 // Leave |writer_| nil
199 }
200 } else {
201 writer_ = [writer retain];
202 }
203 }
204 }
206 - (id<GTMLogFormatter>)formatter {
207 return [[formatter_ retain] autorelease];
208 }
210 - (void)setFormatter:(id<GTMLogFormatter>)formatter {
211 @synchronized(self) {
212 [formatter_ autorelease];
213 formatter_ = nil;
214 if (formatter == nil) {
215 @try {
216 formatter_ = [[GTMLogBasicFormatter alloc] init];
217 }
218 @catch (id e) {
219 // Leave |formatter_| nil
220 }
221 } else {
222 formatter_ = [formatter retain];
223 }
224 }
225 }
227 - (id<GTMLogFilter>)filter {
228 return [[filter_ retain] autorelease];
229 }
231 - (void)setFilter:(id<GTMLogFilter>)filter {
232 @synchronized(self) {
233 [filter_ autorelease];
234 filter_ = nil;
235 if (filter == nil) {
236 @try {
237 filter_ = [[GTMLogNoFilter alloc] init];
238 }
239 @catch (id e) {
240 // Leave |filter_| nil
241 }
242 } else {
243 filter_ = [filter retain];
244 }
245 }
246 }
248 - (void)logDebug:(NSString *)fmt, ... {
249 va_list args;
250 va_start(args, fmt);
251 [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelDebug];
252 va_end(args);
253 }
255 - (void)logInfo:(NSString *)fmt, ... {
256 va_list args;
257 va_start(args, fmt);
258 [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelInfo];
259 va_end(args);
260 }
262 - (void)logError:(NSString *)fmt, ... {
263 va_list args;
264 va_start(args, fmt);
265 [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelError];
266 va_end(args);
267 }
269 - (void)logAssert:(NSString *)fmt, ... {
270 va_list args;
271 va_start(args, fmt);
272 [self logInternalFunc:NULL format:fmt valist:args level:kGTMLoggerLevelAssert];
273 va_end(args);
274 }
276 @end // GTMLogger
278 @implementation GTMLogger (GTMLoggerMacroHelpers)
280 - (void)logFuncDebug:(const char *)func msg:(NSString *)fmt, ... {
281 va_list args;
282 va_start(args, fmt);
283 [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelDebug];
284 va_end(args);
285 }
287 - (void)logFuncInfo:(const char *)func msg:(NSString *)fmt, ... {
288 va_list args;
289 va_start(args, fmt);
290 [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelInfo];
291 va_end(args);
292 }
294 - (void)logFuncError:(const char *)func msg:(NSString *)fmt, ... {
295 va_list args;
296 va_start(args, fmt);
297 [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelError];
298 va_end(args);
299 }
301 - (void)logFuncAssert:(const char *)func msg:(NSString *)fmt, ... {
302 va_list args;
303 va_start(args, fmt);
304 [self logInternalFunc:func format:fmt valist:args level:kGTMLoggerLevelAssert];
305 va_end(args);
306 }
308 @end // GTMLoggerMacroHelpers
310 @implementation GTMLogger (PrivateMethods)
312 - (void)logInternalFunc:(const char *)func
313 format:(NSString *)fmt
314 valist:(va_list)args
315 level:(GTMLoggerLevel)level {
316 // Primary point where logging happens, logging should never throw, catch
317 // everything.
318 @try {
319 NSString *fname = func ? [NSString stringWithUTF8String:func] : nil;
320 NSString *msg = [formatter_ stringForFunc:fname
321 withFormat:fmt
322 valist:args
323 level:level];
324 if (msg && [filter_ filterAllowsMessage:msg level:level])
325 [writer_ logMessage:msg level:level];
326 }
327 @catch (id e) {
328 // Ignored
329 }
330 }
332 @end // PrivateMethods
335 @implementation NSFileHandle (GTMFileHandleLogWriter)
337 + (id)fileHandleForLoggingAtPath:(NSString *)path mode:(mode_t)mode {
338 int fd = -1;
339 if (path) {
340 int flags = O_WRONLY | O_APPEND | O_CREAT;
341 fd = open([path fileSystemRepresentation], flags, mode);
342 }
343 if (fd == -1) return nil;
344 return [[[self alloc] initWithFileDescriptor:fd
345 closeOnDealloc:YES] autorelease];
346 }
348 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
349 @synchronized(self) {
350 // Closed pipes should not generate exceptions in our caller. Catch here
351 // as well [GTMLogger logInternalFunc:...] so that an exception in this
352 // writer does not prevent other writers from having a chance.
353 @try {
354 NSString *line = [NSString stringWithFormat:@"%@\n", msg];
355 [self writeData:[line dataUsingEncoding:NSUTF8StringEncoding]];
356 }
357 @catch (id e) {
358 // Ignored
359 }
360 }
361 }
363 @end // GTMFileHandleLogWriter
366 @implementation NSArray (GTMArrayCompositeLogWriter)
368 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
369 @synchronized(self) {
370 id<GTMLogWriter> child = nil;
371 GTM_FOREACH_OBJECT(child, self) {
372 if ([child conformsToProtocol:@protocol(GTMLogWriter)])
373 [child logMessage:msg level:level];
374 }
375 }
376 }
378 @end // GTMArrayCompositeLogWriter
381 @implementation GTMLogger (GTMLoggerLogWriter)
383 - (void)logMessage:(NSString *)msg level:(GTMLoggerLevel)level {
384 switch (level) {
385 case kGTMLoggerLevelDebug:
386 [self logDebug:@"%@", msg];
387 break;
388 case kGTMLoggerLevelInfo:
389 [self logInfo:@"%@", msg];
390 break;
391 case kGTMLoggerLevelError:
392 [self logError:@"%@", msg];
393 break;
394 case kGTMLoggerLevelAssert:
395 [self logAssert:@"%@", msg];
396 break;
397 default:
398 // Ignore the message.
399 break;
400 }
401 }
403 @end // GTMLoggerLogWriter
406 @implementation GTMLogBasicFormatter
408 - (NSString *)prettyNameForFunc:(NSString *)func {
409 NSString *name = [func stringByTrimmingCharactersInSet:
410 [NSCharacterSet whitespaceAndNewlineCharacterSet]];
411 NSString *function = @"(unknown)";
412 if ([name length]) {
413 if (// Objective C __func__ and __PRETTY_FUNCTION__
414 [name hasPrefix:@"-["] || [name hasPrefix:@"+["] ||
415 // C++ __PRETTY_FUNCTION__ and other preadorned formats
416 [name hasSuffix:@")"]) {
417 function = name;
418 } else {
419 // Assume C99 __func__
420 function = [NSString stringWithFormat:@"%@()", name];
421 }
422 }
423 return function;
424 }
426 - (NSString *)stringForFunc:(NSString *)func
427 withFormat:(NSString *)fmt
428 valist:(va_list)args
429 level:(GTMLoggerLevel)level {
430 // Performance note: We may want to do a quick check here to see if |fmt|
431 // contains a '%', and if not, simply return 'fmt'.
432 if (!(fmt && args)) return nil;
433 return [[[NSString alloc] initWithFormat:fmt arguments:args] autorelease];
434 }
436 @end // GTMLogBasicFormatter
439 @implementation GTMLogStandardFormatter
441 - (id)init {
442 if ((self = [super init])) {
443 dateFormatter_ = [[NSDateFormatter alloc] init];
444 [dateFormatter_ setFormatterBehavior:NSDateFormatterBehavior10_4];
445 [dateFormatter_ setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
446 pname_ = [[[NSProcessInfo processInfo] processName] copy];
447 pid_ = [[NSProcessInfo processInfo] processIdentifier];
448 if (!(dateFormatter_ && pname_)) {
449 [self release];
450 return nil;
451 }
452 }
453 return self;
454 }
456 - (void)dealloc {
457 [dateFormatter_ release];
458 [pname_ release];
459 [super dealloc];
460 }
462 - (NSString *)stringForFunc:(NSString *)func
463 withFormat:(NSString *)fmt
464 valist:(va_list)args
465 level:(GTMLoggerLevel)level {
466 NSString *tstamp = nil;
467 @synchronized (dateFormatter_) {
468 tstamp = [dateFormatter_ stringFromDate:[NSDate date]];
469 }
470 return [NSString stringWithFormat:@"%@ %@[%d/%p] [lvl=%d] %@ %@",
471 tstamp, pname_, pid_, pthread_self(),
472 level, [self prettyNameForFunc:func],
473 // |super| has guard for nil |fmt| and |args|
474 [super stringForFunc:func withFormat:fmt valist:args level:level]];
475 }
477 @end // GTMLogStandardFormatter
480 @implementation GTMLogLevelFilter
482 // Check the environment and the user preferences for the GTMVerboseLogging key
483 // to see if verbose logging has been enabled. The environment variable will
484 // override the defaults setting, so check the environment first.
485 // COV_NF_START
486 static BOOL IsVerboseLoggingEnabled(void) {
487 static NSString *const kVerboseLoggingKey = @"GTMVerboseLogging";
488 NSString *value = [[[NSProcessInfo processInfo] environment]
489 objectForKey:kVerboseLoggingKey];
490 if (value) {
491 // Emulate [NSString boolValue] for pre-10.5
492 value = [value stringByTrimmingCharactersInSet:
493 [NSCharacterSet whitespaceAndNewlineCharacterSet]];
494 if ([[value uppercaseString] hasPrefix:@"Y"] ||
495 [[value uppercaseString] hasPrefix:@"T"] ||
496 [value intValue]) {
497 return YES;
498 } else {
499 return NO;
500 }
501 }
502 return [[NSUserDefaults standardUserDefaults] boolForKey:kVerboseLoggingKey];
503 }
504 // COV_NF_END
506 // In DEBUG builds, log everything. If we're not in a debug build we'll assume
507 // that we're in a Release build.
508 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
509 #if DEBUG
510 return YES;
511 #endif
513 BOOL allow = YES;
515 switch (level) {
516 case kGTMLoggerLevelDebug:
517 allow = NO;
518 break;
519 case kGTMLoggerLevelInfo:
520 allow = IsVerboseLoggingEnabled();
521 break;
522 case kGTMLoggerLevelError:
523 allow = YES;
524 break;
525 case kGTMLoggerLevelAssert:
526 allow = YES;
527 break;
528 default:
529 allow = YES;
530 break;
531 }
533 return allow;
534 }
536 @end // GTMLogLevelFilter
539 @implementation GTMLogNoFilter
541 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
542 return YES; // Allow everything through
543 }
545 @end // GTMLogNoFilter
548 @implementation GTMLogAllowedLevelFilter
550 // Private designated initializer
551 - (id)initWithAllowedLevels:(NSIndexSet *)levels {
552 self = [super init];
553 if (self != nil) {
554 allowedLevels_ = [levels retain];
555 // Cap min/max level
556 if (!allowedLevels_ ||
557 // NSIndexSet is unsigned so only check the high bound, but need to
558 // check both first and last index because NSIndexSet appears to allow
559 // wraparound.
560 ([allowedLevels_ firstIndex] > kGTMLoggerLevelAssert) ||
561 ([allowedLevels_ lastIndex] > kGTMLoggerLevelAssert)) {
562 [self release];
563 return nil;
564 }
565 }
566 return self;
567 }
569 - (id)init {
570 // Allow all levels in default init
571 return [self initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
572 NSMakeRange(kGTMLoggerLevelUnknown,
573 (kGTMLoggerLevelAssert - kGTMLoggerLevelUnknown + 1))]];
574 }
576 - (void)dealloc {
577 [allowedLevels_ release];
578 [super dealloc];
579 }
581 - (BOOL)filterAllowsMessage:(NSString *)msg level:(GTMLoggerLevel)level {
582 return [allowedLevels_ containsIndex:level];
583 }
585 @end // GTMLogAllowedLevelFilter
588 @implementation GTMLogMininumLevelFilter
590 - (id)initWithMinimumLevel:(GTMLoggerLevel)level {
591 return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
592 NSMakeRange(level,
593 (kGTMLoggerLevelAssert - level + 1))]];
594 }
596 @end // GTMLogMininumLevelFilter
599 @implementation GTMLogMaximumLevelFilter
601 - (id)initWithMaximumLevel:(GTMLoggerLevel)level {
602 return [super initWithAllowedLevels:[NSIndexSet indexSetWithIndexesInRange:
603 NSMakeRange(kGTMLoggerLevelUnknown, level + 1)]];
604 }
606 @end // GTMLogMaximumLevelFilter
608 #if !defined(__clang__) && (__GNUC__*10+__GNUC_MINOR__ >= 42)
609 // See comment at top of file.
610 #pragma GCC diagnostic error "-Wmissing-format-attribute"
611 #endif // !__clang__