summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Schleifer <js@heap.zone>2019-10-01 02:40:48 +0200
committerJonathan Schleifer <js@heap.zone>2019-10-01 02:40:48 +0200
commit6b1978714587a94219ae134404d9086b4dd11b8c (patch)
treebbe6edb90722243734fb49607b714d8216fde35e
parent9866ea74a3446129fb15d724654386e305e600bd (diff)
Add OFDNSRequest
-rw-r--r--src/Makefile3
-rw-r--r--src/OFDNSRequest.h96
-rw-r--r--src/OFDNSRequest.m121
-rw-r--r--src/OFDNSResolver.h36
-rw-r--r--src/OFDNSResolver.m371
-rw-r--r--src/OFDNSResponse.h6
-rw-r--r--src/OFDNSResponse.m6
-rw-r--r--src/OFLHADecompressingStream.h2
-rw-r--r--src/ObjFW.h2
-rw-r--r--src/exceptions/Makefile4
-rw-r--r--src/exceptions/OFDNSRequestFailedException.h68
-rw-r--r--src/exceptions/OFDNSRequestFailedException.m (renamed from src/exceptions/OFResolveHostFailedException.m)33
-rw-r--r--src/exceptions/OFResolveHostFailedException.h87
-rw-r--r--utils/ofdns/OFDNS.m10
-rw-r--r--utils/ofhttp/OFHTTP.m8
-rw-r--r--utils/ofhttp/lang/de.json4
16 files changed, 504 insertions, 353 deletions
diff --git a/src/Makefile b/src/Makefile
index b1cba0d9..4d98df1c 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -135,7 +135,8 @@ SRCS_FILES = OFFile.m \
OFSettings.m \
OFString+PathAdditions.m
SRCS_PLUGINS = OFPlugin.m
-SRCS_SOCKETS = OFDNSResolver.m \
+SRCS_SOCKETS = OFDNSRequest.m \
+ OFDNSResolver.m \
OFDNSResourceRecord.m \
OFDNSResponse.m \
OFHTTPClient.m \
diff --git a/src/OFDNSRequest.h b/src/OFDNSRequest.h
new file mode 100644
index 00000000..70679e66
--- /dev/null
+++ b/src/OFDNSRequest.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2018, 2019
+ * Jonathan Schleifer <js@heap.zone>
+ *
+ * All rights reserved.
+ *
+ * This file is part of ObjFW. It may be distributed under the terms of the
+ * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
+ * the packaging of this file.
+ *
+ * Alternatively, it may be distributed under the terms of the GNU General
+ * Public License, either version 2 or 3, which can be found in the file
+ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
+ * file.
+ */
+
+#import "OFObject.h"
+#import "OFDNSResourceRecord.h"
+
+OF_ASSUME_NONNULL_BEGIN
+
+/*!
+ * @class OFDNSRequest OFDNSRequest.h ObjFW/OFDNSRequest.h
+ *
+ * @brief A class representing a DNS request.
+ */
+@interface OFDNSRequest: OFObject <OFCopying>
+{
+ OFString *_host;
+ of_dns_resource_record_class_t _recordClass;
+ of_dns_resource_record_type_t _recordType;
+ OF_RESERVE_IVARS(4)
+}
+
+/*!
+ * @brief The host to resolve.
+ */
+@property (readonly, nonatomic) OFString *host;
+
+/*!
+ * @brief The requested record class.
+ */
+@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass;
+
+/*!
+ * @brief The requested record type.
+ */
+@property (readonly, nonatomic) of_dns_resource_record_type_t recordType;
+
+/*!
+ * @brief Creates a new, autoreleased OFDNSRequest with IN class and type ALL.
+ *
+ * @param host The host to resolve
+ * @return A new, autoreleased OFDNSRequest.
+ */
++ (instancetype)requestWithHost: (OFString *)host;
+
+/*!
+ * @brief Creates a new, autoreleased OFDNSRequest.
+ *
+ * @param host The host to resolve
+ * @param recordClass The requested record class
+ * @param recordType The requested record type
+ * @return A new, autoreleased OFDNSRequest.
+ */
++ (instancetype)requestWithHost: (OFString *)host
+ recordClass: (of_dns_resource_record_class_t)recordClass
+ recordType: (of_dns_resource_record_type_t)recordType;
+
+/*!
+ * @brief Initializes an already allocated OFDNSRequest with IN class and type
+ * ALL.
+ *
+ * @param host The host to resolve
+ * @return An initialized OFDNSRequest
+ */
+- (instancetype)initWithHost: (OFString *)host;
+
+/*!
+ * @brief Initializes an already allocated OFDNSRequest.
+ *
+ * @param host The host to resolve
+ * @param recordClass The requested record class
+ * @param recordType The requested record type
+ * @return An initialized OFDNSRequest
+ */
+- (instancetype)initWithHost: (OFString *)host
+ recordClass: (of_dns_resource_record_class_t)recordClass
+ recordType: (of_dns_resource_record_type_t)recordType
+ OF_DESIGNATED_INITIALIZER;
+
+- (instancetype)init OF_UNAVAILABLE;
+@end
+
+OF_ASSUME_NONNULL_END
diff --git a/src/OFDNSRequest.m b/src/OFDNSRequest.m
new file mode 100644
index 00000000..c037f86e
--- /dev/null
+++ b/src/OFDNSRequest.m
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2018, 2019
+ * Jonathan Schleifer <js@heap.zone>
+ *
+ * All rights reserved.
+ *
+ * This file is part of ObjFW. It may be distributed under the terms of the
+ * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
+ * the packaging of this file.
+ *
+ * Alternatively, it may be distributed under the terms of the GNU General
+ * Public License, either version 2 or 3, which can be found in the file
+ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
+ * file.
+ */
+
+#include "config.h"
+
+#import "OFDNSRequest.h"
+#import "OFString.h"
+
+@implementation OFDNSRequest
+@synthesize host = _host, recordClass = _recordClass, recordType = _recordType;
+
++ (instancetype)requestWithHost: (OFString *)host
+{
+ return [[[self alloc] initWithHost: host] autorelease];
+}
+
++ (instancetype)requestWithHost: (OFString *)host
+ recordClass: (of_dns_resource_record_class_t)recordClass
+ recordType: (of_dns_resource_record_type_t)recordType
+{
+ return [[[self alloc] initWithHost: host
+ recordClass: recordClass
+ recordType: recordType] autorelease];
+}
+
+- (instancetype)initWithHost: (OFString *)host
+{
+ return [self initWithHost: host
+ recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
+ recordType: OF_DNS_RESOURCE_RECORD_TYPE_ALL];
+}
+
+- (instancetype)initWithHost: (OFString *)host
+ recordClass: (of_dns_resource_record_class_t)recordClass
+ recordType: (of_dns_resource_record_type_t)recordType
+{
+ self = [super init];
+
+ @try {
+ _host = [host copy];
+ _recordClass = recordClass;
+ _recordType = recordType;
+ } @catch (id e) {
+ [self release];
+ @throw e;
+ }
+
+ return self;
+}
+
+- (instancetype)init
+{
+ OF_INVALID_INIT_METHOD
+}
+
+- (void)dealloc
+{
+ [_host release];
+
+ [super dealloc];
+}
+
+- (bool)isEqual: (id)object
+{
+ OFDNSRequest *request;
+
+ if (![object isKindOfClass: [OFDNSRequest class]])
+ return false;
+
+ request = object;
+
+ if (request->_host != _host && ![request->_host isEqual: _host])
+ return false;
+ if (request->_recordClass != _recordClass)
+ return false;
+ if (request->_recordType != _recordType)
+ return false;
+
+ return true;
+}
+
+- (uint32_t)hash
+{
+ uint32_t hash;
+
+ OF_HASH_INIT(hash);
+ OF_HASH_ADD_HASH(hash, _host.hash);
+ OF_HASH_ADD(hash, _recordClass);
+ OF_HASH_ADD(hash, _recordType);
+ OF_HASH_FINALIZE(hash);
+
+ return hash;
+}
+
+- (id)copy
+{
+ return [self retain];
+}
+
+- (OFString *)description
+{
+ return [OFString stringWithFormat: @"<%@ %@ %@ %@>",
+ self.className, _host,
+ of_dns_resource_record_class_to_string(_recordClass),
+ of_dns_resource_record_type_to_string(_recordType)];
+}
+@end
diff --git a/src/OFDNSResolver.h b/src/OFDNSResolver.h
index 255eede7..89155600 100644
--- a/src/OFDNSResolver.h
+++ b/src/OFDNSResolver.h
@@ -16,6 +16,7 @@
*/
#import "OFObject.h"
+#import "OFDNSRequest.h"
#import "OFDNSResourceRecord.h"
#import "OFDNSResponse.h"
#import "OFRunLoop.h"
@@ -200,41 +201,24 @@ OF_SUBCLASSING_RESTRICTED
- (instancetype)init;
/*!
- * @brief Asynchronously resolves the specified host.
+ * @brief Asynchronously performs the specified request.
*
- * @param host The host to resolve
- * @param delegate The delegate to use for callbacks
- */
-- (void)asyncResolveHost: (OFString *)host
- delegate: (id <OFDNSResolverDelegate>)delegate;
-
-/*!
- * @brief Asynchronously resolves the specified host.
- *
- * @param host The host to resolve
- * @param recordClass The desired class of the records to query
- * @param recordType The desired type of the records to query
+ * @param request The request to perform
* @param delegate The delegate to use for callbacks
*/
-- (void)asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- delegate: (id <OFDNSResolverDelegate>)delegate;
+- (void)asyncPerformRequest: (OFDNSRequest *)request
+ delegate: (id <OFDNSResolverDelegate>)delegate;
/*!
- * @brief Asynchronously resolves the specified host.
+ * @brief Asynchronously performs the specified request.
*
- * @param host The host to resolve
- * @param recordClass The desired class of the records to query
- * @param recordType The desired type of the records to query
+ * @param request The request to perform
* @param runLoopMode The run loop mode in which to resolve
* @param delegate The delegate to use for callbacks
*/
-- (void)asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- delegate: (id <OFDNSResolverDelegate>)delegate;
+- (void)asyncPerformRequest: (OFDNSRequest *)request
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ delegate: (id <OFDNSResolverDelegate>)delegate;
/*!
* @brief Asynchronously resolves the specified host to socket addresses.
diff --git a/src/OFDNSResolver.m b/src/OFDNSResolver.m
index 818da8d5..660d6b00 100644
--- a/src/OFDNSResolver.m
+++ b/src/OFDNSResolver.m
@@ -24,6 +24,8 @@
#import "OFDNSResolver.h"
#import "OFArray.h"
#import "OFCharacterSet.h"
+#import "OFDNSRequest.h"
+#import "OFDNSResponse.h"
#import "OFData.h"
#import "OFDate.h"
#import "OFDictionary.h"
@@ -39,6 +41,7 @@
# import "OFWindowsRegistryKey.h"
#endif
+#import "OFDNSRequestFailedException.h"
#import "OFInitializationFailedException.h"
#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
@@ -46,7 +49,6 @@
#import "OFOpenItemFailedException.h"
#import "OFOutOfMemoryException.h"
#import "OFOutOfRangeException.h"
-#import "OFResolveHostFailedException.h"
#import "OFTruncatedDataException.h"
#ifdef OF_WINDOWS
@@ -121,9 +123,8 @@ static const of_run_loop_mode_t resolveRunLoopMode =
@interface OFDNSResolverQuery: OFObject
{
@public
- OFString *_host, *_domainName;
- of_dns_resource_record_class_t _recordClass;
- of_dns_resource_record_type_t _recordType;
+ OFDNSRequest *_request;
+ OFString *_domainName;
OFNumber *_ID;
OFDNSResolverSettings *_settings;
size_t _nameServersIndex, _searchDomainsIndex;
@@ -136,17 +137,15 @@ static const of_run_loop_mode_t resolveRunLoopMode =
OFTimer *_cancelTimer;
}
-- (instancetype)initWithHost: (OFString *)host
- domainName: (OFString *)domainName
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- ID: (OFNumber *)ID
- settings: (OFDNSResolverSettings *)settings
- nameServersIndex: (size_t)nameServersIndex
- searchDomainsIndex: (size_t)searchDomainsIndex
- target: (id)target
- selector: (SEL)selector
- context: (id)context;
+- (instancetype)initWithRequest: (OFDNSRequest *)request
+ domainName: (OFString *)domainName
+ ID: (OFNumber *)ID
+ settings: (OFDNSResolverSettings *)settings
+ nameServersIndex: (size_t)nameServersIndex
+ searchDomainsIndex: (size_t)searchDomainsIndex
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context;
@end
@interface OFDNSResolverAsyncResolveSocketAddressesContext: OFObject
@@ -215,23 +214,19 @@ static const of_run_loop_mode_t resolveRunLoopMode =
- (void)of_obtainNintendo3DSSytemConfig;
#endif
- (void)of_reloadSystemConfig;
-- (void)of_resolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- settings: (OFDNSResolverSettings *)settings
- nameServersIndex: (size_t)nameServersIndex
- searchDomainsIndex: (size_t)searchDomainsIndex
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- target: (id)target
- selector: (SEL)selector
- context: (id)context;
-- (void)of_asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- target: (id)target
- selector: (SEL)selector
- context: (id)context;
+- (void)of_asyncPerformRequest: (OFDNSRequest *)request
+ settings: (OFDNSResolverSettings *)settings
+ nameServersIndex: (size_t)nameServersIndex
+ searchDomainsIndex: (size_t)searchDomainsIndex
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context;
+- (void)of_asyncPerformRequest: (OFDNSRequest *)request
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context;
- (void)of_sendQuery: (OFDNSResolverQuery *)query
runLoopMode: (of_run_loop_mode_t)runLoopMode;
- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query;
@@ -698,17 +693,15 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
@end
@implementation OFDNSResolverQuery
-- (instancetype)initWithHost: (OFString *)host
- domainName: (OFString *)domainName
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- ID: (OFNumber *)ID
- settings: (OFDNSResolverSettings *)settings
- nameServersIndex: (size_t)nameServersIndex
- searchDomainsIndex: (size_t)searchDomainsIndex
- target: (id)target
- selector: (SEL)selector
- context: (id)context
+- (instancetype)initWithRequest: (OFDNSRequest *)request
+ domainName: (OFString *)domainName
+ ID: (OFNumber *)ID
+ settings: (OFDNSResolverSettings *)settings
+ nameServersIndex: (size_t)nameServersIndex
+ searchDomainsIndex: (size_t)searchDomainsIndex
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context
{
self = [super init];
@@ -717,10 +710,8 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
OFMutableData *queryData;
uint16_t tmp;
- _host = [host copy];
+ _request = [request copy];
_domainName = [domainName copy];
- _recordClass = recordClass;
- _recordType = recordType;
_ID = [ID retain];
_settings = [settings retain];
_nameServersIndex = nameServersIndex;
@@ -733,7 +724,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
/* Header */
- tmp = OF_BSWAP16_IF_LE(ID.uInt16Value);
+ tmp = OF_BSWAP16_IF_LE(_ID.uInt16Value);
[queryData addItems: &tmp
count: 2];
@@ -754,7 +745,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
/* QNAME */
for (OFString *component in
- [domainName componentsSeparatedByString: @"."]) {
+ [_domainName componentsSeparatedByString: @"."]) {
size_t length = component.UTF8StringLength;
uint8_t length8;
@@ -768,14 +759,14 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
}
/* QTYPE */
- tmp = OF_BSWAP16_IF_LE(recordType);
+ tmp = OF_BSWAP16_IF_LE(_request.recordType);
[queryData addItems: &tmp
count: 2];
/* QCLASS */
- tmp = OF_BSWAP16_IF_LE(recordClass);
+ tmp = OF_BSWAP16_IF_LE(_request.recordClass);
[queryData addItems: &tmp
- count: 2];
+ count: 2];
[queryData makeImmutable];
@@ -792,7 +783,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
- (void)dealloc
{
- [_host release];
+ [_request release];
[_domainName release];
[_ID release];
[_settings release];
@@ -895,6 +886,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
[OFRunLoop currentRunLoop].currentMode;
OFNumber *recordTypeNumber =
[OFNumber numberWithInt: recordType];
+ OFDNSRequest *request;
_expectedResponses++;
@@ -902,15 +894,17 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
[OFPair pairWithFirstObject: CNAME
secondObject: recordTypeNumber]];
- [_resolver of_asyncResolveHost: alias
- recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
- recordType: recordType
- runLoopMode: runLoopMode
- target: self
- selector: @selector(resolver:
- didResolveCNAME:response:
- context:exception:)
- context: recordTypeNumber];
+ request = [OFDNSRequest
+ requestWithHost: alias
+ recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
+ recordType: recordType];
+ [_resolver of_asyncPerformRequest: request
+ runLoopMode: runLoopMode
+ target: self
+ selector: @selector(resolver:
+ didResolveCNAME:response:
+ context:exception:)
+ context: recordTypeNumber];
}
}
@@ -1009,12 +1003,16 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
[addresses makeImmutable];
- if (addresses.count == 0)
- exception = [OFResolveHostFailedException
- exceptionWithHost: _host
- recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
- recordType: 0
- error: OF_DNS_RESOLVER_ERROR_UNKNOWN];
+ if (addresses.count == 0) {
+ OFDNSRequest *request = [OFDNSRequest
+ requestWithHost: _host
+ recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
+ recordType: 0];
+
+ exception = [OFDNSRequestFailedException
+ exceptionWithRequest: request
+ error: OF_DNS_RESOLVER_ERROR_UNKNOWN];
+ }
if ([_delegate respondsToSelector: @selector(
resolver:didResolveDomainName:socketAddresses:exception:)])
@@ -1569,20 +1567,18 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
[self of_obtainSystemConfig];
}
-- (void)of_resolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- settings: (OFDNSResolverSettings *)settings
- nameServersIndex: (size_t)nameServersIndex
- searchDomainsIndex: (size_t)searchDomainsIndex
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- target: (id)target
- selector: (SEL)selector
- context: (id)context
+- (void)of_asyncPerformRequest: (OFDNSRequest *)request
+ settings: (OFDNSResolverSettings *)settings
+ nameServersIndex: (size_t)nameServersIndex
+ searchDomainsIndex: (size_t)searchDomainsIndex
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context
{
void *pool = objc_autoreleasePoolPush();
OFNumber *ID;
- OFString *domainName;
+ OFString *host, *domainName;
OFDNSResolverQuery *query;
[self of_reloadSystemConfig];
@@ -1592,6 +1588,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
ID = [OFNumber numberWithUInt16: (uint16_t)of_random()];
} while ([_queries objectForKey: ID] != nil);
+ host = request.host;
if (isFQDN(host, settings)) {
domainName = host;
@@ -1609,17 +1606,15 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
@throw [OFOutOfRangeException exception];
query = [[[OFDNSResolverQuery alloc]
- initWithHost: host
- domainName: domainName
- recordClass: recordClass
- recordType: recordType
- ID: ID
- settings: settings
- nameServersIndex: nameServersIndex
- searchDomainsIndex: searchDomainsIndex
- target: target
- selector: selector
- context: context] autorelease];
+ initWithRequest: request
+ domainName: domainName
+ ID: ID
+ settings: settings
+ nameServersIndex: nameServersIndex
+ searchDomainsIndex: searchDomainsIndex
+ target: target
+ selector: selector
+ context: context] autorelease];
[_queries setObject: query
forKey: ID];
@@ -1643,57 +1638,36 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
exception: exception];
}
-- (void)asyncResolveHost: (OFString *)host
- delegate: (id <OFDNSResolverDelegate>)delegate
+- (void)asyncPerformRequest: (OFDNSRequest *)request
+ delegate: (id <OFDNSResolverDelegate>)delegate
{
- [self of_asyncResolveHost: host
- recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
- recordType: OF_DNS_RESOURCE_RECORD_TYPE_ALL
- runLoopMode: of_run_loop_mode_default
- target: self
- selector: @selector(of_resolver:didResolveDomainName:
- response:context:exception:)
- context: delegate];
+ [self of_asyncPerformRequest: request
+ runLoopMode: of_run_loop_mode_default
+ target: self
+ selector: @selector(of_resolver:
+ didResolveDomainName:response:context:
+ exception:)
+ context: delegate];
}
-- (void)asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- delegate: (id <OFDNSResolverDelegate>)delegate
-{
- [self of_asyncResolveHost: host
- recordClass: recordClass
- recordType: recordType
- runLoopMode: of_run_loop_mode_default
- target: self
- selector: @selector(of_resolver:didResolveDomainName:
- response:context:exception:)
- context: delegate];
-}
-
-- (void)asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- delegate: (id <OFDNSResolverDelegate>)delegate
+- (void)asyncPerformRequest: (OFDNSRequest *)request
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ delegate: (id <OFDNSResolverDelegate>)delegate
{
- [self of_asyncResolveHost: host
- recordClass: recordClass
- recordType: recordType
- runLoopMode: runLoopMode
- target: self
- selector: @selector(of_resolver:didResolveDomainName:
- response:context:exception:)
- context: delegate];
+ [self of_asyncPerformRequest: request
+ runLoopMode: runLoopMode
+ target: self
+ selector: @selector(of_resolver:
+ didResolveDomainName:response:context:
+ exception:)
+ context: delegate];
}
-- (void)of_asyncResolveHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- runLoopMode: (of_run_loop_mode_t)runLoopMode
- target: (id)target
- selector: (SEL)selector
- context: (id)context
+- (void)of_asyncPerformRequest: (OFDNSRequest *)request
+ runLoopMode: (of_run_loop_mode_t)runLoopMode
+ target: (id)target
+ selector: (SEL)selector
+ context: (id)context
{
void *pool = objc_autoreleasePoolPush();
OFDNSResolverSettings *settings = [[[OFDNSResolverSettings alloc]
@@ -1704,16 +1678,14 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
minNumberOfDotsInAbsoluteName: _minNumberOfDotsInAbsoluteName]
autorelease];
- [self of_resolveHost: host
- recordClass: recordClass
- recordType: recordType
- settings: settings
- nameServersIndex: 0
- searchDomainsIndex: 0
- runLoopMode: runLoopMode
- target: target
- selector: selector
- context: context];
+ [self of_asyncPerformRequest: request
+ settings: settings
+ nameServersIndex: 0
+ searchDomainsIndex: 0
+ runLoopMode: runLoopMode
+ target: target
+ selector: selector
+ context: context];
objc_autoreleasePoolPop(pool);
}
@@ -1788,7 +1760,7 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
- (void)of_queryWithIDTimedOut: (OFDNSResolverQuery *)query
{
- OFResolveHostFailedException *exception;
+ OFDNSRequestFailedException *exception;
if (query == nil)
return;
@@ -1825,11 +1797,9 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
length: BUFFER_LENGTH];
#endif
- exception = [OFResolveHostFailedException
- exceptionWithHost: query->_host
- recordClass: query->_recordClass
- recordType: query->_recordType
- error: OF_DNS_RESOLVER_ERROR_TIMEOUT];
+ exception = [OFDNSRequestFailedException
+ exceptionWithRequest: query->_request
+ error: OF_DNS_RESOLVER_ERROR_TIMEOUT];
callback(query->_target, query->_selector, self, query->_domainName,
nil, query->_context, exception);
@@ -1912,19 +1882,21 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
query->_settings->_searchDomains.count) {
of_run_loop_mode_t runLoopMode =
[OFRunLoop currentRunLoop].currentMode;
+ size_t nameServersIndex =
+ query->_nameServersIndex;
+ size_t searchDomainsIndex =
+ query->_searchDomainsIndex;
query->_searchDomainsIndex++;
- [self of_resolveHost: query->_host
- recordClass: query->_recordClass
- recordType: query->_recordType
- settings: query->_settings
- nameServersIndex: query->_nameServersIndex
- searchDomainsIndex: query->_searchDomainsIndex
- runLoopMode: runLoopMode
- target: query->_target
- selector: query->_selector
- context: query->_context];
+ [self of_asyncPerformRequest: query->_request
+ settings: query->_settings
+ nameServersIndex: nameServersIndex
+ searchDomainsIndex: searchDomainsIndex
+ runLoopMode: runLoopMode
+ target: query->_target
+ selector: query->_selector
+ context: query->_context];
return true;
}
@@ -1943,11 +1915,9 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
}
if (buffer[3] & 0x0F)
- @throw [OFResolveHostFailedException
- exceptionWithHost: query->_host
- recordClass: query->_recordClass
- recordType: query->_recordType
- error: error];
+ @throw [OFDNSRequestFailedException
+ exceptionWithRequest: query->_request
+ error: error];
numQuestions = (buffer[4] << 8) | buffer[5];
numAnswers = (buffer[6] << 8) | buffer[7];
@@ -2103,12 +2073,14 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
OF_DNS_RESOURCE_RECORD_CLASS_IN;
of_dns_resolver_error_t error =
OF_DNS_RESOLVER_ERROR_NO_RESULT;
-
- exception = [OFResolveHostFailedException
- exceptionWithHost: host
- recordClass: recordClass
- recordType: recordType
- error: error];
+ OFDNSRequest *request = [OFDNSRequest
+ requestWithHost: host
+ recordClass: recordClass
+ recordType: recordType];
+
+ exception = [OFDNSRequestFailedException
+ exceptionWithRequest: request
+ error: error];
}
}
@@ -2160,33 +2132,40 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
#ifdef OF_HAVE_IPV6
if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV6 ||
addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) {
+ OFDNSRequest *request = [OFDNSRequest
+ requestWithHost: host
+ recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
+ recordType: OF_DNS_RESOURCE_RECORD_TYPE_AAAA];
OFNumber *recordTypeNumber =
[OFNumber numberWithInt: OF_DNS_RESOURCE_RECORD_TYPE_AAAA];
- [self of_asyncResolveHost: host
- recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
- recordType: OF_DNS_RESOURCE_RECORD_TYPE_AAAA
- runLoopMode: runLoopMode
- target: context
- selector: @selector(resolver:
- didResolveDomainName:
- response:context:exception:)
- context: recordTypeNumber];
+ [self of_asyncPerformRequest: request
+ runLoopMode: runLoopMode
+ target: context
+ selector: @selector(resolver:
+ didResolveDomainName:response:
+ context:exception:)
+ context: recordTypeNumber];
}
#endif
if (addressFamily == OF_SOCKET_ADDRESS_FAMILY_IPV4 ||
- addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY)
- [self of_asyncResolveHost: host
- recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
- recordType: OF_DNS_RESOURCE_RECORD_TYPE_A
- runLoopMode: runLoopMode
- target: context
- selector: @selector(resolver:
- didResolveDomainName:
- response:context:exception:)
- context: [OFNumber numberWithInt:
- OF_DNS_RESOURCE_RECORD_TYPE_A]];
+ addressFamily == OF_SOCKET_ADDRESS_FAMILY_ANY) {
+ OFDNSRequest *request = [OFDNSRequest
+ requestWithHost: host
+ recordClass: OF_DNS_RESOURCE_RECORD_CLASS_IN
+ recordType: OF_DNS_RESOURCE_RECORD_TYPE_A];
+ OFNumber *recordTypeNumber =
+ [OFNumber numberWithInt: OF_DNS_RESOURCE_RECORD_TYPE_A];
+
+ [self of_asyncPerformRequest: request
+ runLoopMode: runLoopMode
+ target: context
+ selector: @selector(resolver:
+ didResolveDomainName:response:
+ context:exception:)
+ context: recordTypeNumber];
+ }
objc_autoreleasePoolPop(pool);
}
@@ -2244,13 +2223,11 @@ callback(id target, SEL selector, OFDNSResolver *resolver, OFString *domainName,
enumerator = [_queries objectEnumerator];
while ((query = [enumerator nextObject]) != nil) {
- OFResolveHostFailedException *exception;
+ OFDNSRequestFailedException *exception;
- exception = [OFResolveHostFailedException
- exceptionWithHost: query->_host
- recordClass: query->_recordClass
- recordType: query->_recordType
- error: OF_DNS_RESOLVER_ERROR_CANCELED];
+ exception = [OFDNSRequestFailedException
+ exceptionWithRequest: query->_request
+ error: OF_DNS_RESOLVER_ERROR_CANCELED];
callback(query->_target, query->_selector, self,
query->_domainName, nil, query->_context, exception);
diff --git a/src/OFDNSResponse.h b/src/OFDNSResponse.h
index 937604f2..dab755b5 100644
--- a/src/OFDNSResponse.h
+++ b/src/OFDNSResponse.h
@@ -42,19 +42,19 @@ typedef OFDictionary OF_GENERIC(OFString *, OFArray OF_GENERIC(
/*!
* @brief The answer records of the response.
*/
-@property OF_NULLABLE_PROPERTY (nonatomic, readonly)
+@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
of_dns_response_records_t answerRecords;
/*!
* @brief The authority records of the response.
*/
-@property OF_NULLABLE_PROPERTY (nonatomic, readonly)
+@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
of_dns_response_records_t authorityRecords;
/*!
* @brief The additional records of the response.
*/
-@property OF_NULLABLE_PROPERTY (nonatomic, readonly)
+@property OF_NULLABLE_PROPERTY (readonly, nonatomic)
of_dns_response_records_t additionalRecords;
/*!
diff --git a/src/OFDNSResponse.m b/src/OFDNSResponse.m
index 38e4b725..c90babad 100644
--- a/src/OFDNSResponse.m
+++ b/src/OFDNSResponse.m
@@ -82,11 +82,9 @@
if (other->_answerRecords != _answerRecords &&
![other->_answerRecords isEqual: _answerRecords])
return false;
-
if (other->_authorityRecords != _authorityRecords &&
![other->_authorityRecords isEqual: _authorityRecords])
return false;
-
if (other->_additionalRecords != _additionalRecords &&
![other->_additionalRecords isEqual: _additionalRecords])
return false;
@@ -120,11 +118,11 @@
withString: @"\n\t"];
return [OFString stringWithFormat:
- @"<OFDNSResponse:\n"
+ @"<%@:\n"
@"\tAnswer records = %@\n"
@"\tAuthority records = %@\n"
@"\tAdditional records = %@\n"
@">",
- answerRecords, authorityRecords, additionalRecords];
+ self.className, answerRecords, authorityRecords, additionalRecords];
}
@end
diff --git a/src/OFLHADecompressingStream.h b/src/OFLHADecompressingStream.h
index e116f979..036578c7 100644
--- a/src/OFLHADecompressingStream.h
+++ b/src/OFLHADecompressingStream.h
@@ -44,7 +44,7 @@ OF_ASSUME_NONNULL_BEGIN
uint32_t _distance;
}
-@property (nonatomic, readonly) uint32_t bytesConsumed;
+@property (readonly, nonatomic) uint32_t bytesConsumed;
- (instancetype)of_initWithStream: (OFStream *)stream
distanceBits: (uint8_t)distanceBits
diff --git a/src/ObjFW.h b/src/ObjFW.h
index 507ca644..993837d3 100644
--- a/src/ObjFW.h
+++ b/src/ObjFW.h
@@ -147,7 +147,7 @@
# import "OFAcceptFailedException.h"
# import "OFAlreadyConnectedException.h"
# import "OFBindFailedException.h"
-# import "OFResolveHostFailedException.h"
+# import "OFDNSRequestFailedException.h"
#endif
#import "OFChangeCurrentDirectoryPathFailedException.h"
#import "OFChecksumMismatchException.h"
diff --git a/src/exceptions/Makefile b/src/exceptions/Makefile
index 9a8597b9..096ece38 100644
--- a/src/exceptions/Makefile
+++ b/src/exceptions/Makefile
@@ -58,10 +58,10 @@ SRCS_SOCKETS = OFAcceptFailedException.m \
OFAlreadyConnectedException.m \
OFBindFailedException.m \
OFConnectionFailedException.m \
+ OFDNSRequestFailedException.m \
OFHTTPRequestFailedException.m \
OFListenFailedException.m \
- OFObserveFailedException.m \
- OFResolveHostFailedException.m
+ OFObserveFailedException.m
SRCS_THREADS = OFConditionBroadcastFailedException.m \
OFConditionSignalFailedException.m \
OFConditionStillWaitingException.m \
diff --git a/src/exceptions/OFDNSRequestFailedException.h b/src/exceptions/OFDNSRequestFailedException.h
new file mode 100644
index 00000000..b52a3de7
--- /dev/null
+++ b/src/exceptions/OFDNSRequestFailedException.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
+ * 2018, 2019
+ * Jonathan Schleifer <js@heap.zone>
+ *
+ * All rights reserved.
+ *
+ * This file is part of ObjFW. It may be distributed under the terms of the
+ * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
+ * the packaging of this file.
+ *
+ * Alternatively, it may be distributed under the terms of the GNU General
+ * Public License, either version 2 or 3, which can be found in the file
+ * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
+ * file.
+ */
+
+#import "OFException.h"
+#import "OFDNSRequest.h"
+#import "OFDNSResolver.h"
+#import "OFDNSResourceRecord.h"
+
+OF_ASSUME_NONNULL_BEGIN
+
+/*!
+ * @class OFDNSRequestFailedException \
+ * OFDNSRequestFailedException.h ObjFW/OFDNSRequestFailedException.h
+ *
+ * @brief An exception indicating the resolving a host failed.
+ */
+@interface OFDNSRequestFailedException: OFException
+{
+ OFDNSRequest *_request;
+ of_dns_resolver_error_t _error;
+}
+
+/*!
+ * @brief The request which could not be performed.
+ */
+@property (readonly, nonatomic) OFDNSRequest *request;
+
+/*!
+ * @brief The error from the resolver.
+ */
+@property (readonly, nonatomic) of_dns_resolver_error_t error;
+
+/*!
+ * @brief Creates a new, autoreleased resolve host failed exception.
+ *
+ * @param request The request which could not be performed
+ * @param error The error from the resolver
+ * @return A new, autoreleased address translation failed exception
+ */
++ (instancetype)exceptionWithRequest: (OFDNSRequest *)request
+ error: (of_dns_resolver_error_t)error;
+
+/*!
+ * @brief Initializes an already allocated address translation failed exception.
+ *
+ * @param request The request which could not be performed
+ * @param error The error from the resolver
+ * @return An initialized address translation failed exception
+ */
+- (instancetype)initWithRequest: (OFDNSRequest *)request
+ error: (of_dns_resolver_error_t)error;
+@end
+
+OF_ASSUME_NONNULL_END
diff --git a/src/exceptions/OFResolveHostFailedException.m b/src/exceptions/OFDNSRequestFailedException.m
index aa49e52d..34cc34a6 100644
--- a/src/exceptions/OFResolveHostFailedException.m
+++ b/src/exceptions/OFDNSRequestFailedException.m
@@ -17,35 +17,26 @@
#include "config.h"
-#import "OFResolveHostFailedException.h"
+#import "OFDNSRequestFailedException.h"
#import "OFString.h"
-@implementation OFResolveHostFailedException
-@synthesize host = _host, recordClass = _recordClass, recordType = _recordType;
-@synthesize error = _error;
+@implementation OFDNSRequestFailedException
+@synthesize request = _request, error = _error;
-+ (instancetype)exceptionWithHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- error: (of_dns_resolver_error_t)error
++ (instancetype)exceptionWithRequest: (OFDNSRequest *)request
+ error: (of_dns_resolver_error_t)error
{
- return [[[self alloc] initWithHost: host
- recordClass: recordClass
- recordType: recordType
- error: error] autorelease];
+ return [[[self alloc] initWithRequest: request
+ error: error] autorelease];
}
-- (instancetype)initWithHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- error: (of_dns_resolver_error_t)error
+- (instancetype)initWithRequest: (OFDNSRequest *)request
+ error: (of_dns_resolver_error_t)error
{
self = [super init];
@try {
- _host = [host copy];
- _recordClass = recordClass;
- _recordType = recordType;
+ _request = [request copy];
_error = error;
} @catch (id e) {
[self release];
@@ -57,7 +48,7 @@
- (void)dealloc
{
- [_host release];
+ [_request release];
[super dealloc];
}
@@ -100,6 +91,6 @@
}
return [OFString stringWithFormat:
- @"The host %@ could not be resolved: %@", _host, error];
+ @"Request %@ could not be performed: %@", _request, error];
}
@end
diff --git a/src/exceptions/OFResolveHostFailedException.h b/src/exceptions/OFResolveHostFailedException.h
deleted file mode 100644
index 1cf9fc4c..00000000
--- a/src/exceptions/OFResolveHostFailedException.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017,
- * 2018, 2019
- * Jonathan Schleifer <js@heap.zone>
- *
- * All rights reserved.
- *
- * This file is part of ObjFW. It may be distributed under the terms of the
- * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
- * the packaging of this file.
- *
- * Alternatively, it may be distributed under the terms of the GNU General
- * Public License, either version 2 or 3, which can be found in the file
- * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
- * file.
- */
-
-#import "OFException.h"
-#import "OFDNSResolver.h"
-#import "OFDNSResourceRecord.h"
-
-OF_ASSUME_NONNULL_BEGIN
-
-/*!
- * @class OFResolveHostFailedException \
- * OFResolveHostFailedException.h ObjFW/OFResolveHostFailedException.h
- *
- * @brief An exception indicating the resolving a host failed.
- */
-@interface OFResolveHostFailedException: OFException
-{
- OFString *_host;
- of_dns_resource_record_class_t _recordClass;
- of_dns_resource_record_type_t _recordType;
- of_dns_resolver_error_t _error;
-}
-
-/*!
- * @brief The host which could not be resolved.
- */
-@property (readonly, nonatomic) OFString *host;
-
-/*!
- * @brief The class code for the resource record to resolve to.
- */
-@property (readonly, nonatomic) of_dns_resource_record_class_t recordClass;
-
-/*!
- * @brief The type code for the resource record to resolve to.
- */
-@property (readonly, nonatomic) of_dns_resource_record_type_t recordType;
-
-/*!
- * @brief The error from the resolver.
- */
-@property (readonly, nonatomic) of_dns_resolver_error_t error;
-
-/*!
- * @brief Creates a new, autoreleased resolve host failed exception.
- *
- * @param host The host which could not be resolved
- * @param recordClass The class code for the resource record to resolve to
- * @param recordType The type code for the resource record to resolve to
- * @param error The error from the resolver
- * @return A new, autoreleased address translation failed exception
- */
-+ (instancetype)exceptionWithHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- error: (of_dns_resolver_error_t)error;
-
-/*!
- * @brief Initializes an already allocated address translation failed exception.
- *
- * @param host The host for which translation was requested
- * @param recordClass The class code for the resource record to resolve to
- * @param recordType The type code for the resource record to resolve to
- * @param error The error from the resolver
- * @return An initialized address translation failed exception
- */
-- (instancetype)initWithHost: (OFString *)host
- recordClass: (of_dns_resource_record_class_t)recordClass
- recordType: (of_dns_resource_record_type_t)recordType
- error: (of_dns_resolver_error_t)error;
-@end
-
-OF_ASSUME_NONNULL_END
diff --git a/utils/ofdns/OFDNS.m b/utils/ofdns/OFDNS.m
index 89f7dea3..a3b22d8d 100644
--- a/utils/ofdns/OFDNS.m
+++ b/utils/ofdns/OFDNS.m
@@ -53,6 +53,7 @@ OF_APPLICATION_DELEGATE(OFDNS)
OF_DNS_RESOURCE_RECORD_CLASS_ANY;
of_dns_resource_record_type_t recordType =
OF_DNS_RESOURCE_RECORD_TYPE_ALL;
+ OFDNSRequest *request;
OFDNSResolver *resolver;
#ifdef OF_HAVE_SANDBOX
@@ -90,9 +91,10 @@ OF_APPLICATION_DELEGATE(OFDNS)
[arguments objectsInRange: of_range(3, 1)];
}
- [resolver asyncResolveHost: [arguments objectAtIndex: 0]
- recordClass: recordClass
- recordType: recordType
- delegate: self];
+ request = [OFDNSRequest requestWithHost: [arguments objectAtIndex: 0]
+ recordClass: recordClass
+ recordType: recordType];
+ [resolver asyncPerformRequest: request
+ delegate: self];
}
@end
diff --git a/utils/ofhttp/OFHTTP.m b/utils/ofhttp/OFHTTP.m
index dc4fe1d4..67d73e35 100644
--- a/utils/ofhttp/OFHTTP.m
+++ b/utils/ofhttp/OFHTTP.m
@@ -36,13 +36,13 @@
#import "OFURL.h"
#import "OFConnectionFailedException.h"
+#import "OFDNSRequestFailedException.h"
#import "OFHTTPRequestFailedException.h"
#import "OFInvalidFormatException.h"
#import "OFInvalidServerReplyException.h"
#import "OFOpenItemFailedException.h"
#import "OFOutOfRangeException.h"
#import "OFReadFailedException.h"
-#import "OFResolveHostFailedException.h"
#import "OFRetrieveItemAttributesFailedException.h"
#import "OFUnsupportedProtocolException.h"
#import "OFWriteFailedException.h"
@@ -612,14 +612,14 @@ fileNameFromContentDisposition(OFString *contentDisposition)
didFailWithException: (id)e
request: (OFHTTPRequest *)request
{
- if ([e isKindOfClass: [OFResolveHostFailedException class]]) {
+ if ([e isKindOfClass: [OFDNSRequestFailedException class]]) {
if (!_quiet)
[of_stdout writeString: @"\n"];
[of_stderr writeLine:
- OF_LOCALIZED(@"download_failed_resolve_host_failed",
+ OF_LOCALIZED(@"download_dns_request_failed",
@"%[prog]: Failed to download <%[url]>!\n"
- @" Failed to resolve host: %[exception]",
+ @" DNS request failed: %[exception]",
@"prog", [OFApplication programName],
@"url", request.URL.string,
@"exception", e)];
diff --git a/utils/ofhttp/lang/de.json b/utils/ofhttp/lang/de.json
index cd3998df..3c9a706a 100644
--- a/utils/ofhttp/lang/de.json
+++ b/utils/ofhttp/lang/de.json
@@ -38,9 +38,9 @@
"%[prog]: -o / --output kann nicht mit mehr als einer URL benutzt ",
"werden!"
],
- "download_failed_resolve_host_failed": [
+ "download_dns_request_failed": [
"%[prog]: Fehler beim Download von <%[url]>!\n",
- " Adressauflösung fehlgeschlagen: %[exception]"
+ " DNS-Anfrage fehlgeschlagen: %[exception]"
],
"download_failed_connection_failed": [
"%[prog]: Fehler beim Download von <%[url]>!\n",