Search code examples
iosswiftamazon-s3nsurlsessionurlsession

Swift URL Session Response gets corrupted when using '&' symbol


I am developing iOS app, I am using URL Session method for make API calls. Api response gives one property which contains AWS s3 link for pdf document.

What should happen: So in this app, I am retrieving a PDF document from the server to view in the app, so in the GET URL that I'm sending will give a response of an access link of the pdf document generated through AWS S3.

What is happening now:

Document name: Document/sdd3343-sfnf0asdnd0UserB&ServiceLetter.pdf (notice there is an '&' sign)

In the android and Swagger application, this GET URL is working perfect on any circumstances. but in the iOS version- in the URL session, when ever when there is a '&' sign inside the document's name, the responding access link gets corrupted.

Now in Android and Swagger, when we are accessing the same document, it works perfectly, but for iOS it doesn't.

URL that doesn't work on iOS but that works in Android and Swagger:

https://domainName/api/FileUpload/GetDocumentUrl?S3Key=**Document/sdd3343-sfnf0asdnd0UserB&ServiceLetter.pdf**&fileCategory=2&userId=9888900000

Above url having parameter name called 'S3Key' value is Document/sdd3343 sfnf0asdnd0UserB&ServiceLetter.pdf and it having an ampersand '&' symbol in middle of the name.

iOS response for the above URL:

{"success":true,"response":"https://samplesite.s3.ap-southwest-2.amazonaws.com/Document/sdd3343-sfnf0asdnd0UserB?X-Amz-Expires=3600&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAWEWNDEFIENS88NKWSWIULHKA/20221010/ap-southwest-2/s3/aws4_request&X-Amz-Date=20221010T011135Z&X-Amz-SignedHeaders=host&X-Amz-Signature=44cab95333c0b5e385959835948539845948023823483","error":null}

In here you can see the response which got by the URL Session. But the reponse url body cut off from ampersand symbol.

Current Response: /Document/sdd3343-sfnf0asdnd0UserB?X-Amz-Expires=3600&X.........

Expected Response: /Document/sdd3343-sfnf0asdnd0UserB&ServiceLetter.pdf?X-Amz-Expires=3600&X.........

How to solve this URL Session problem


Solution

  • Note how & characters are used to separate key/value pairs in a URL. Because of this, you cannot have an & in the middle of a value within a URL, because it is interpreted as a delimiter before the next key/value pair. The answer is to percent-escape the & in the value associated with the S3Key key. To do this, the easiest way is URLComponents:

    guard var components = URLComponents(string: "https://domainName/api/FileUpload/GetDocumentUrl") else {
        print("URLComponents failure")
        return
    }
    
    components.queryItems = [
        URLQueryItem(name: "S3Key", value: "Document/sdd3343-sfnf0asdnd0UserB&ServiceLetter.pdf"),
        URLQueryItem(name: "fileCategory", value: "2"),
        URLQueryItem(name: "userId", value: "9888900000")
    ]
    
    guard let url = components.url else {
        print("unable to build url")
        return
    }
    
    print(url) // https://domainName/api/FileUpload/GetDocumentUrl?S3Key=Document/sdd3343-sfnf0asdnd0UserB%26ServiceLetter.pdf&fileCategory=2&userId=9888900000
    

    There are other ways to manually percent-escape the values in the URL, but URLComponents does it reasonably gracefully.