/*
 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. 
 */

#import "config.h"
#import "ResourceError.h"

#import <CoreFoundation/CFError.h>
#import <Foundation/Foundation.h>
#import <wtf/BlockObjCExceptions.h>
#import <wtf/NeverDestroyed.h>
#import <wtf/URL.h>
#import <wtf/text/WTFString.h>

@interface NSError (WebExtras)
- (NSString *)_web_localizedDescription;
@end

#if PLATFORM(IOS_FAMILY)

// This workaround code exists here because we can't call translateToCFError in Foundation. Once we
// have that, we can remove this code. <rdar://problem/9837415> Need SPI for translateCFError
// The code is mostly identical to Foundation - I changed the class name and fixed minor compile errors.
// We need this because client code (Safari) wants an NSError with NSURLErrorDomain as its domain.
// The Foundation code below does that and sets up appropriate certificate keys in the NSError.

@interface WebCustomNSURLError : NSError

@end

@implementation WebCustomNSURLError

static NSDictionary* dictionaryThatCanCode(NSDictionary* src)
{
    // This function makes a copy of input dictionary, modifies it such that it "should" (as much as we can help it)
    // not contain any objects that do not conform to NSCoding protocol, and returns it autoreleased.

    NSMutableDictionary* dst = [src mutableCopy];

    // Kill the known problem entries.
    [dst removeObjectForKey:@"NSErrorPeerCertificateChainKey"]; // NSArray with SecCertificateRef objects
    [dst removeObjectForKey:@"NSErrorClientCertificateChainKey"]; // NSArray with SecCertificateRef objects
    [dst removeObjectForKey:NSURLErrorFailingURLPeerTrustErrorKey]; // SecTrustRef object
    [dst removeObjectForKey:NSUnderlyingErrorKey]; // (Immutable) CFError containing kCF equivalent of the above
    // We could reconstitute this but it's more trouble than it's worth

    // Non-comprehensive safety check:  Kill top-level dictionary entries that don't conform to NSCoding.
    // We may hit ones we just removed, but that's fine.
    // We don't handle arbitrary objects that clients have stuffed into the dictionary, since we may not know how to
    // get at its conents (e.g., a CFError object -- you'd have to know it had a userInfo dictionary and kill things
    // inside it).
    [src enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL*) {
        if (! [obj conformsToProtocol:@protocol(NSCoding)]) {
            [dst removeObjectForKey:key];
        }
        // FIXME: We could drill down into subdictionaries, but it seems more trouble than it's worth
    }];

    return [dst autorelease];
}

- (void)encodeWithCoder:(NSCoder *)coder
{
    NSDictionary* newUserInfo = dictionaryThatCanCode([self userInfo]);

    [[NSError errorWithDomain:[self domain] code:[self code] userInfo:newUserInfo] encodeWithCoder:coder];
}

@end

#endif // PLATFORM(IOS_FAMILY)

namespace WebCore {

static RetainPtr<NSError> createNSErrorFromResourceErrorBase(const ResourceErrorBase& resourceError)
{
    RetainPtr<NSMutableDictionary> userInfo = adoptNS([[NSMutableDictionary alloc] init]);

    if (!resourceError.localizedDescription().isEmpty())
        [userInfo.get() setValue:resourceError.localizedDescription() forKey:NSLocalizedDescriptionKey];

    if (!resourceError.failingURL().isEmpty()) {
        [userInfo.get() setValue:(NSString *)resourceError.failingURL().string() forKey:@"NSErrorFailingURLStringKey"];
        if (NSURL *cocoaURL = (NSURL *)resourceError.failingURL())
            [userInfo.get() setValue:cocoaURL forKey:@"NSErrorFailingURLKey"];
    }

    return adoptNS([[NSError alloc] initWithDomain:resourceError.domain() code:resourceError.errorCode() userInfo:userInfo.get()]);
}

ResourceError::ResourceError(NSError *nsError)
    : ResourceErrorBase(Type::Null)
    , m_dataIsUpToDate(false)
    , m_platformError(nsError)
{
    mapPlatformError();
}

ResourceError::ResourceError(CFErrorRef cfError)
    : ResourceError { (__bridge NSError *)cfError }
{
}

const String& ResourceError::getNSURLErrorDomain() const
{
    static const NeverDestroyed<String> errorDomain(NSURLErrorDomain);
    return errorDomain.get();
}

const String& ResourceError::getCFErrorDomainCFNetwork() const
{
    static const NeverDestroyed<String> errorDomain(kCFErrorDomainCFNetwork);
    return errorDomain.get();
}

void ResourceError::mapPlatformError()
{
    static_assert(NSURLErrorTimedOut == kCFURLErrorTimedOut, "NSURLErrorTimedOut needs to equal kCFURLErrorTimedOut");
    static_assert(NSURLErrorCancelled == kCFURLErrorCancelled, "NSURLErrorCancelled needs to equal kCFURLErrorCancelled");

    if (!m_platformError)
        return;

    auto domain = [m_platformError.get() domain];
    auto errorCode = [m_platformError.get() code];

    if ([domain isEqualToString:NSURLErrorDomain] || [domain isEqualToString:(__bridge NSString *)kCFErrorDomainCFNetwork])
        setType((errorCode == NSURLErrorTimedOut) ? Type::Timeout : (errorCode == NSURLErrorCancelled) ? Type::Cancellation : Type::General);
    else
        setType(Type::General);
}

void ResourceError::platformLazyInit()
{
    if (m_dataIsUpToDate)
        return;

    m_domain = [m_platformError.get() domain];
    m_errorCode = [m_platformError.get() code];

    if (NSString* failingURLString = [[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLStringKey"])
        m_failingURL = URL(URL(), failingURLString);
    else
        m_failingURL = URL((NSURL *)[[m_platformError.get() userInfo] valueForKey:@"NSErrorFailingURLKey"]);
    // Workaround for <rdar://problem/6554067>
    m_localizedDescription = m_failingURL;
    BEGIN_BLOCK_OBJC_EXCEPTIONS;
    m_localizedDescription = [m_platformError.get() _web_localizedDescription];
    END_BLOCK_OBJC_EXCEPTIONS;

    m_dataIsUpToDate = true;
}

bool ResourceError::platformCompare(const ResourceError& a, const ResourceError& b)
{
    return a.nsError() == b.nsError();
}

void ResourceError::doPlatformIsolatedCopy(const ResourceError&)
{
}

NSError *ResourceError::nsError() const
{
    if (isNull()) {
        ASSERT(!m_platformError);
        return nil;
    }

    if (!m_platformError)
        m_platformError = createNSErrorFromResourceErrorBase(*this);

    return m_platformError.get();
}

ResourceError::operator NSError *() const
{
    return nsError();
}

CFErrorRef ResourceError::cfError() const
{
    return (__bridge CFErrorRef)nsError();
}

ResourceError::operator CFErrorRef() const
{
    return cfError();
}

} // namespace WebCore
