From ee2520f2c0c2d806fd284c3d6b8a81a3822f5270 Mon Sep 17 00:00:00 2001 From: Christian Cleberg Date: Mon, 20 Apr 2026 15:28:12 -0500 Subject: feat(v1.8): improve result structure, history, and consistency - normalize sections and add summary card - fix resolver usage in reverse DNS - include custom port scans in history/export - standardize error handling - decompose ContentView into smaller views --- DomainDig/HTTPHeadersService.swift | 61 +++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 28 deletions(-) (limited to 'DomainDig/HTTPHeadersService.swift') diff --git a/DomainDig/HTTPHeadersService.swift b/DomainDig/HTTPHeadersService.swift index 51e7b5b..4bf175a 100644 --- a/DomainDig/HTTPHeadersService.swift +++ b/DomainDig/HTTPHeadersService.swift @@ -35,41 +35,46 @@ struct HTTPHeadersResult { } struct HTTPHeadersService { - static func fetch(domain: String) async throws -> HTTPHeadersResult { + static func fetch(domain: String) async -> ServiceResult { let url = URL(string: "https://\(domain)")! var request = URLRequest(url: url, timeoutInterval: 10) request.httpMethod = "HEAD" let metricsDelegate = TaskMetricsDelegate() let startTime = Date() - let (_, response) = try await URLSession.shared.data(for: request, delegate: metricsDelegate) - let responseTimeMs = max(0, Int(Date().timeIntervalSince(startTime) * 1000)) - - guard let httpResponse = response as? HTTPURLResponse else { - throw URLError(.badServerResponse) - } - - let headers = httpResponse.allHeaderFields.compactMap { entry -> HTTPHeader? in - guard let name = entry.key as? String, - let value = entry.value as? String else { return nil } - return HTTPHeader(name: name, value: value) + do { + let (_, response) = try await URLSession.shared.data(for: request, delegate: metricsDelegate) + let responseTimeMs = max(0, Int(Date().timeIntervalSince(startTime) * 1000)) + + guard let httpResponse = response as? HTTPURLResponse else { + return .error(URLError(.badServerResponse).localizedDescription) + } + + let headers = httpResponse.allHeaderFields.compactMap { entry -> HTTPHeader? in + guard let name = entry.key as? String, + let value = entry.value as? String else { return nil } + return HTTPHeader(name: name, value: value) + } + .sorted { $0.name.lowercased() < $1.name.lowercased() } + + let networkProtocolName = metricsDelegate.metrics?.transactionMetrics + .compactMap { $0.networkProtocolName } + .last + let detectedProtocol = protocolLabel(for: networkProtocolName) + let altSvcValue = headerValue(named: "alt-svc", in: httpResponse) + let http3Advertised = altSvcValue?.localizedCaseInsensitiveContains("h3") == true + let result = HTTPHeadersResult( + headers: headers, + statusCode: httpResponse.statusCode, + responseTimeMs: responseTimeMs, + httpProtocol: detectedProtocol, + http3Advertised: http3Advertised + ) + + return headers.isEmpty ? .empty("No HTTP headers returned") : .success(result) + } catch { + return .error(error.localizedDescription) } - .sorted { $0.name.lowercased() < $1.name.lowercased() } - - let networkProtocolName = metricsDelegate.metrics?.transactionMetrics - .compactMap { $0.networkProtocolName } - .last - let detectedProtocol = protocolLabel(for: networkProtocolName) - let altSvcValue = headerValue(named: "alt-svc", in: httpResponse) - let http3Advertised = altSvcValue?.localizedCaseInsensitiveContains("h3") == true - - return HTTPHeadersResult( - headers: headers, - statusCode: httpResponse.statusCode, - responseTimeMs: responseTimeMs, - httpProtocol: detectedProtocol, - http3Advertised: http3Advertised - ) } private static func protocolLabel(for networkProtocolName: String?) -> String? { -- cgit v1.2.3