From 4ee7509964ab0e49e74c6f9558c523d0e8634522 Mon Sep 17 00:00:00 2001 From: Olena Stepaniuk <92721590+OlenaPostindustria@users.noreply.github.com> Date: Tue, 15 Aug 2023 10:13:56 +0300 Subject: [PATCH] Handle URL double encoding & replace bid price on Native Ad (#902) * feat: handle double encoding & replace bid price on Native Ad * test: update test signature --- PrebidMobile.xcodeproj/project.pbxproj | 4 +++ PrebidMobile/AdUnits/Native/NativeAd.swift | 7 ++-- .../String+Extensions.swift | 13 ++++++++ PrebidMobile/TrackerManager.swift | 12 +++---- .../StringExtensionsTest.swift | 33 +++++++++++++++++++ 5 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 PrebidMobileTests/RenderingTests/Tests/UtilitiesExtensionsTests/StringExtensionsTest.swift diff --git a/PrebidMobile.xcodeproj/project.pbxproj b/PrebidMobile.xcodeproj/project.pbxproj index f7b716f12..6e530c1ab 100644 --- a/PrebidMobile.xcodeproj/project.pbxproj +++ b/PrebidMobile.xcodeproj/project.pbxproj @@ -75,6 +75,7 @@ 533FDF852A12030C0066ED5A /* MockPrebidJSLibraryManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 533FDF842A12030C0066ED5A /* MockPrebidJSLibraryManager.swift */; }; 5355ACA929C454070014F16E /* VAST_with_empty_companion.xml in Resources */ = {isa = PBXBuildFile; fileRef = 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */; }; 5355ACAB29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */; }; + 536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */; }; 536A427F282D11DA0069E9B2 /* PrebidServerConnection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A427E282D11DA0069E9B2 /* PrebidServerConnection.swift */; }; 536A4283282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536A4282282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift */; }; 537B6518283372FD008AE9D1 /* PathBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537B6517283372FD008AE9D1 /* PathBuilder.swift */; }; @@ -911,6 +912,7 @@ 533FDF842A12030C0066ED5A /* MockPrebidJSLibraryManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrebidJSLibraryManager.swift; sourceTree = ""; }; 5355ACA829C454070014F16E /* VAST_with_empty_companion.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = VAST_with_empty_companion.xml; sourceTree = ""; }; 5355ACAA29C454770014F16E /* CreativeModelCollectionMakerVASTTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreativeModelCollectionMakerVASTTests.swift; sourceTree = ""; }; + 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StringExtensionsTest.swift; sourceTree = ""; }; 536A427E282D11DA0069E9B2 /* PrebidServerConnection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidServerConnection.swift; sourceTree = ""; }; 536A4282282D12E80069E9B2 /* PrebidServerConnectionProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrebidServerConnectionProtocol.swift; sourceTree = ""; }; 537B6517283372FD008AE9D1 /* PathBuilder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathBuilder.swift; sourceTree = ""; }; @@ -2973,6 +2975,7 @@ 925D5E542737F2A900A8A2B5 /* PBMFunctionsPrivateTest.m */, 925D5E562737F2D900A8A2B5 /* PBMMacrosTest.m */, 925D5E582737F35500A8A2B5 /* UIViewExtensionsTest.swift */, + 536A39252A84C50F00B1CCEA /* StringExtensionsTest.swift */, ); path = UtilitiesExtensionsTests; sourceTree = ""; @@ -3807,6 +3810,7 @@ 925D5E302737ED8C00A8A2B5 /* PBMRewardedVideoViewTest.swift in Sources */, 922AFCCB27353B9A00732C53 /* MockServerRule.m in Sources */, 925D5D872737BAB300A8A2B5 /* PBMOpenMeasurementWrapperTest.swift in Sources */, + 536A39262A84C50F00B1CCEA /* StringExtensionsTest.swift in Sources */, 925D5E782737F60100A8A2B5 /* VastEventTrackingTest.swift in Sources */, 533FDF852A12030C0066ED5A /* MockPrebidJSLibraryManager.swift in Sources */, 922AFD452737298200732C53 /* PBMHTMLCreativeTest_MRAIDPlayVideo.swift in Sources */, diff --git a/PrebidMobile/AdUnits/Native/NativeAd.swift b/PrebidMobile/AdUnits/Native/NativeAd.swift index 9c3f1ec6c..242098d98 100644 --- a/PrebidMobile/AdUnits/Native/NativeAd.swift +++ b/PrebidMobile/AdUnits/Native/NativeAd.swift @@ -109,6 +109,10 @@ public class NativeAd: NSObject, CacheExpiryDelegate { return nil } + let macrosHelper = PBMORTBMacrosHelper(bid: rawBid) + rawBid.adm = macrosHelper.replaceMacros(in: rawBid.adm) + rawBid.nurl = macrosHelper.replaceMacros(in: rawBid.nurl) + let ad = NativeAd() let internalEventTracker = PrebidServerEventTracker() @@ -293,8 +297,7 @@ public class NativeAd: NSObject, CacheExpiryDelegate { @objc private func handleClick() { self.delegate?.adWasClicked?(ad: self) if let clickUrl = nativeAdMarkup?.link?.url, - let clickUrlString = clickUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), - let url = URL(string: clickUrlString) { + let url = clickUrl.encodedURL(with: .urlQueryAllowed) { if openURLWithExternalBrowser(url: url) { if let clickTrackers = nativeAdMarkup?.link?.clicktrackers { fireClickTrackers(clickTrackersUrls: clickTrackers) diff --git a/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/String+Extensions.swift b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/String+Extensions.swift index ad27e29c6..a0605326a 100644 --- a/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/String+Extensions.swift +++ b/PrebidMobile/PrebidMobileRendering/ExtensionsAndWrappers/String+Extensions.swift @@ -27,4 +27,17 @@ extension String { return false } + + func encodedURL(with characterSet: CharacterSet) -> URL? { + if let url = URL(string: self) { + return url + } + + if let encodedURLString = addingPercentEncoding(withAllowedCharacters: characterSet), + let url = URL(string: encodedURLString) { + return url + } + + return nil + } } diff --git a/PrebidMobile/TrackerManager.swift b/PrebidMobile/TrackerManager.swift index 7ab01448b..7959819ec 100644 --- a/PrebidMobile/TrackerManager.swift +++ b/PrebidMobile/TrackerManager.swift @@ -66,8 +66,7 @@ class TrackerManager: NSObject { Log.debug("Internet is reachable - FIRING TRACKERS: \(arrayWithURLs)") arrayWithURLs.forEach { urlString in - if let clickUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: clickUrlString) - { + if let url = urlString.encodedURL(with: .urlQueryAllowed) { let request = URLRequest(url: url) URLSession.shared.dataTask(with: request) { [weak self] data, _, error in guard error == nil else { @@ -80,12 +79,11 @@ class TrackerManager: NSObject { return } if let completion = completion { - completion(true) + completion(true) } }.resume() } } - } private func queueTrackerURLForRetry(URL: String, completion: OnComplete){ @@ -120,12 +118,15 @@ class TrackerManager: NSObject { trackerArray.removeAll() trackerRetryTimer?.invalidate() } + if trackerArrayCopy?.count != 0 { trackerArrayCopy?.forEach({ info in if info.expired{ return } - if let urlString = info.URL, let clickUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: clickUrlString) + + if let urlString = info.URL, + let url = urlString.encodedURL(with: .urlQueryAllowed) { let request = URLRequest(url: url) URLSession.shared.dataTask(with: request) { [weak self] data, _, error in @@ -151,7 +152,6 @@ class TrackerManager: NSObject { } }.resume() } - }) } } diff --git a/PrebidMobileTests/RenderingTests/Tests/UtilitiesExtensionsTests/StringExtensionsTest.swift b/PrebidMobileTests/RenderingTests/Tests/UtilitiesExtensionsTests/StringExtensionsTest.swift new file mode 100644 index 000000000..dc5c5e631 --- /dev/null +++ b/PrebidMobileTests/RenderingTests/Tests/UtilitiesExtensionsTests/StringExtensionsTest.swift @@ -0,0 +1,33 @@ +/*   Copyright 2018-2023 Prebid.org, Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +import XCTest +@testable import PrebidMobile + +class StringExtensionsTest: XCTestCase { + + func testEncodeURL() { + let str1 = "https://example.com/search?q=Prebid mobile&page=1" + let encodedStr1 = str1.encodedURL(with: .urlQueryAllowed)?.absoluteString + + XCTAssertNotEqual(str1, encodedStr1) + XCTAssertTrue(encodedStr1!.contains("%20")) + + let str2 = "https://example.com/search?q=Prebid%20mobile&page=1" + let encodedStr2 = str2.encodedURL(with: .urlQueryAllowed)?.absoluteString + + XCTAssertEqual(str2, encodedStr2) + } +}