Skip to content

Commit

Permalink
Merge pull request #24 from Flipkart/lowercased_headers
Browse files Browse the repository at this point in the history
added support for lowercased headers
  • Loading branch information
naveen-c authored Nov 9, 2023
2 parents 8182be4 + a5a5d9a commit 028967d
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 11 deletions.
12 changes: 9 additions & 3 deletions Sources/Core/Swifty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ struct SwiftyInterceptors {
/// Concurrent Network Queue having a utility QOS.
let networkQueue = DispatchQueue(label: "swifty.networkOperations", qos: .utility, attributes: [.concurrent])

/// If the header should be sent and read in lowercase
let lowercasedHTTPHeaders: Bool

/// Initialize Swifty with the given URLSession, Constraints, and Request & Response Interceptors
///
/// The constraints and interceptors passed in these arguments will run in same order as passed in these arrays.
Expand All @@ -55,11 +58,13 @@ struct SwiftyInterceptors {
public init(session: URLSession,
constraints: [Constraint] = [],
requestInterceptors: [RequestInterceptor] = [],
responseInterceptors: [ResponseInterceptor] = []) {
responseInterceptors: [ResponseInterceptor] = [],
lowercasedHTTPHeaders: Bool = false) {
self.session = session
self.constraints = constraints
self.requestInterceptors = SwiftyInterceptors.requestInterceptors + requestInterceptors
self.responseInterceptors = SwiftyInterceptors.responseInteptors + responseInterceptors
self.lowercasedHTTPHeaders = lowercasedHTTPHeaders
super.init()
}

Expand All @@ -76,15 +81,16 @@ struct SwiftyInterceptors {
constraints: [Constraint] = [],
requestInterceptors: [RequestInterceptor] = [],
responseInterceptors: [ResponseInterceptor] = [],
sessionMetricsDelegate: URLSessionTaskDelegate? = nil) {
sessionMetricsDelegate: URLSessionTaskDelegate? = nil,
lowercasedHTTPHeaders: Bool = false) {

#if DEBUG
let session = URLSession(configuration: configuration, delegate: sessionMetricsDelegate ?? SwiftyURLSessionDelegate.shared, delegateQueue: nil)
#else
let session = URLSession(configuration: configuration, delegate: sessionMetricsDelegate, delegateQueue: nil)
#endif

self.init(session: session, constraints: constraints, requestInterceptors: requestInterceptors, responseInterceptors: responseInterceptors)
self.init(session: session, constraints: constraints, requestInterceptors: requestInterceptors, responseInterceptors: responseInterceptors, lowercasedHTTPHeaders: lowercasedHTTPHeaders)
}

/// Adds a network resource to run on the Swifty Queue.
Expand Down
21 changes: 21 additions & 0 deletions Sources/Extensions/HTTPURLResponse+Headers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// HTTPURLResponse+Headers.swift
// Swifty
//
// Created by Suhaas Kumbhajadala on 19/07/23.
// Copyright © 2023 Swifty. All rights reserved.
//

import Foundation

extension HTTPURLResponse {
public var lowercasedHTTPHeaders: [String: String] {
var headers: [String: String] = [:]
for header in self.allHeaderFields {
if let fieldName = header.key as? String, let value = self.allHeaderFields[header.key] as? String {
headers[fieldName.lowercased()] = value
}
}
return headers
}
}
4 changes: 2 additions & 2 deletions Sources/Inspector/SwiftyInspectorDetailTableView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ class SwiftyInspectorDetailTableView: UITableViewController {
var contentType: String?
if let headers = task.currentRequest?.allHTTPHeaderFields {
for (_, key) in headers.keys.enumerated() {
requestHeaders.append("\(key): \(headers[key]!)\n")
requestHeaders.append("\(key.lowercased()): \(headers[key]!)\n")
if(key == "Content-Type") {
contentType = headers[key]
contentType = headers[key.lowercased()]
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions Sources/WebService/NetworkResource+Modifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public extension NetworkResource {

if let data = "\(username):\(password)".data(using: .utf8) {
let credential = data.base64EncodedString(options: [])
self.header(key: "Authorization", value: "Basic \(credential)")
self.header(key: self.lowercasedHTTPHeaders ? "authorization" : "Authorization", value: "Basic \(credential)")
} else {
print("NetworkResource: Failed to encode authorization header for \(username): \(password)")
}
Expand Down Expand Up @@ -72,7 +72,7 @@ public extension NetworkResource {
print("NetworkResource: Didn't add header for key: \(key), since the value provided was empty.")
return self
}
self.request.setValue(value, forHTTPHeaderField: key)
self.request.setValue(value, forHTTPHeaderField: self.lowercasedHTTPHeaders ? key.lowercased() : key)
return self
}

Expand All @@ -88,7 +88,7 @@ public extension NetworkResource {

dictionary.forEach({ (key, value) in
if(!value.isEmpty) {
self.request.setValue(value, forHTTPHeaderField: key)
self.request.setValue(value, forHTTPHeaderField: self.lowercasedHTTPHeaders ? key.lowercased() : key)
} else {
print("NetworkResource: Didn't add header for key: \(key) in the provided headers, since the value provided was empty.")
}
Expand Down Expand Up @@ -185,7 +185,7 @@ public extension NetworkResource {
/// - Parameter contentType: Content-Type
/// - Returns: NetworkResource
@objc @discardableResult func contentType(_ contentType: String) -> NetworkResource {
self.request.setValue(contentType, forHTTPHeaderField: "Content-Type")
self.request.setValue(contentType, forHTTPHeaderField: self.lowercasedHTTPHeaders ? "content-type": "Content-Type")
return self
}

Expand Down
4 changes: 4 additions & 0 deletions Sources/WebService/NetworkResource.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ import Foundation

var multipartData: [BodyPart]?

/// If headers should be in lowercase
let lowercasedHTTPHeaders: Bool

/// Error (if any) encountered while Webservice was creating this request.
///
/// Set this error in your own extensions of `NetworkResource` or `NetworkResourceWithBody` Modifiers to inform callers of errors that fail the request, for example, JSON encoding failures.
Expand Down Expand Up @@ -82,6 +85,7 @@ import Foundation
@objc public init(request: NSMutableURLRequest, networkInterface: WebServiceNetworkInterface? = nil) {
self.request = request
self.networkInterface = networkInterface
self.lowercasedHTTPHeaders = Swifty.shared.lowercasedHTTPHeaders
}

/// Initializes the NetworkResource with the given URLRequest
Expand Down
14 changes: 12 additions & 2 deletions Swifty.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@
16AB33C51F7F9B570046AA09 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AB33C31F7F9B560046AA09 /* Utility.swift */; };
16AB33C61F7F9B570046AA09 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AB33C31F7F9B560046AA09 /* Utility.swift */; };
16AB33C71F7F9B570046AA09 /* Utility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 16AB33C31F7F9B560046AA09 /* Utility.swift */; };
46A216A32A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */; };
46A216A42A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */; };
46A216A52A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */; };
46A216A62A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */; };
52D6D9871BEFF229002C0205 /* Swifty.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* Swifty.framework */; };
DD7502881C68FEDE006590AF /* Swifty.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* Swifty.framework */; };
DD7502921C690C7A006590AF /* Swifty.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* Swifty.framework */; };
Expand Down Expand Up @@ -159,6 +163,7 @@
16AB33A11F7F9A970046AA09 /* NetworkResource+Loaders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NetworkResource+Loaders.swift"; sourceTree = "<group>"; };
16AB33C11F7F9B0F0046AA09 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
16AB33C31F7F9B560046AA09 /* Utility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utility.swift; sourceTree = "<group>"; };
46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HTTPURLResponse+Headers.swift"; sourceTree = "<group>"; };
52D6D97C1BEFF229002C0205 /* Swifty.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swifty.framework; sourceTree = BUILT_PRODUCTS_DIR; };
52D6D9861BEFF229002C0205 /* Swifty-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Swifty-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
52D6D9E21BEFFF6E002C0205 /* Swifty.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swifty.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -279,6 +284,7 @@
children = (
16AB338B1F7F9A7B0046AA09 /* URLSessionTransactionMetricsExtensions.swift */,
16AB33C31F7F9B560046AA09 /* Utility.swift */,
46A216A22A681CFB00698A71 /* HTTPURLResponse+Headers.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -650,6 +656,7 @@
16AB33981F7F9A800046AA09 /* SwiftyInspectorDetailTableView.swift in Sources */,
16AB33651F7F9A580046AA09 /* ParsingInterceptor.swift in Sources */,
16AB33A61F7F9A9A0046AA09 /* NetworkResourceWithBody.swift in Sources */,
46A216A32A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */,
16AB33991F7F9A800046AA09 /* URLSessionTransactionMetricsExtensions.swift in Sources */,
16AB33661F7F9A580046AA09 /* Swifty.swift in Sources */,
16AB33611F7F9A580046AA09 /* Constraint.swift in Sources */,
Expand Down Expand Up @@ -689,6 +696,7 @@
16AB33921F7F9A7F0046AA09 /* SwiftyInspectorDetailTableView.swift in Sources */,
16AB33791F7F9A590046AA09 /* ParsingInterceptor.swift in Sources */,
16AB33B41F7F9A9B0046AA09 /* NetworkResourceWithBody.swift in Sources */,
46A216A52A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */,
16AB33931F7F9A7F0046AA09 /* URLSessionTransactionMetricsExtensions.swift in Sources */,
16AB337A1F7F9A590046AA09 /* Swifty.swift in Sources */,
16AB33751F7F9A590046AA09 /* Constraint.swift in Sources */,
Expand Down Expand Up @@ -717,6 +725,7 @@
16AB338F1F7F9A7E0046AA09 /* SwiftyInspectorDetailTableView.swift in Sources */,
16AB33831F7F9A5A0046AA09 /* ParsingInterceptor.swift in Sources */,
16AB33BB1F7F9A9C0046AA09 /* NetworkResourceWithBody.swift in Sources */,
46A216A62A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */,
16AB33901F7F9A7E0046AA09 /* URLSessionTransactionMetricsExtensions.swift in Sources */,
16AB33841F7F9A5A0046AA09 /* Swifty.swift in Sources */,
16AB337F1F7F9A5A0046AA09 /* Constraint.swift in Sources */,
Expand Down Expand Up @@ -745,6 +754,7 @@
16AB33951F7F9A7F0046AA09 /* SwiftyInspectorDetailTableView.swift in Sources */,
16AB336F1F7F9A590046AA09 /* ParsingInterceptor.swift in Sources */,
16AB33AD1F7F9A9B0046AA09 /* NetworkResourceWithBody.swift in Sources */,
46A216A42A681CFB00698A71 /* HTTPURLResponse+Headers.swift in Sources */,
16AB33961F7F9A7F0046AA09 /* URLSessionTransactionMetricsExtensions.swift in Sources */,
16AB33701F7F9A590046AA09 /* Swifty.swift in Sources */,
16AB336B1F7F9A590046AA09 /* Constraint.swift in Sources */,
Expand Down Expand Up @@ -926,7 +936,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Configs/Swifty.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
ONLY_ACTIVE_ARCH = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.Swifty.Swifty-iOS";
Expand All @@ -949,7 +959,7 @@
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = Configs/Swifty.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.Swifty.Swifty-iOS";
PRODUCT_NAME = Swifty;
Expand Down

0 comments on commit 028967d

Please sign in to comment.