3

I have my custom URLProtocol, which is having some custom response generation. Now i have a requirement, where in i need send some information to server via httpBody (Can be json/String as data) before getting the actual response

My problem is, when i create urlRequest with httpBody, then fire the service by using URLSession with some session configuration(That custom URLProtocol is included here)

This will call first canInit -> canonical -> startLoading -> stopLoading, inside these all methods the request.httpBody is nil.

override func startLoading() {
        let request = self.request
        var response: HTTPURLResponse?
        let hasResponse: Bool = true
        if request.httpMethod == "GET" || request.httpMethod == "POST" {
            guard let url = request.url else {
                return
            }
            let client = self.client
            let statusCode = 200
            if url.absoluteString.contains("/good") {
                print(self.request.httpBody)  //here its nil
            } 
            response = hasResponse ? HTTPURLResponse(url: request.url!, statusCode: statusCode, httpVersion: "HTTP/1.1", headerFields: cannedHeaders) : nil
            client?.urlProtocol(self, didLoad: responseData)
            client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: URLCache.StoragePolicy.notAllowed)
            client?.urlProtocolDidFinishLoading(self)
        }
    }
func testCompressRequest() {
        let expect = expectation(description: "testCompressRequest")
        let urlRequest = URLRequest(url: URL(string:serverPath+"/good")!)
        urlRequest.httpBody = "someMethodBodyasString".data(using: .utf8)
        urlRequest.httpMethod = "POST"
        urlRequest.allHTTPHeaderFields = ["Accept-Encoding": "gzip, deflate", "Content-Encoding":"gzip, deflate", "Content-Type":"application/json", "Accept":"application/json", "Content-Length":String(describing: urlRequest.httpBody?.count)]
        let task = URLSession(configuration: sessionConfig).dataTask(with: urlRequest) { (data, response, error) in
            expect.fulfill()
        }
        task.resume()
        waitForExpectations(timeout: 10, handler: nil)
    }
nynohu
  • 1,628
  • 12
  • 12
Padalingam
  • 149
  • 6

1 Answers1

4

By the time a protocol sees the request object, the body data object has already been standardized into a body stream object. Open the body stream and read the data from there instead.

dgatwood
  • 10,129
  • 1
  • 28
  • 49
  • i have checked that too. i dont have any avail byte on stream instance – Padalingam Dec 28 '16 at 05:59
  • Normally, if you don't have to modify the body data, instead of opening the stream, you would use it as the body stream value in the new request that you pass to the NSURLSession/NSURLConnection instance that you're using to do the actual work. In your case, though, since you're actually reading the data yourself, I *think* you have to do that asynchronously, because the writer is likely running asynchronously on the same thread as your reader, and thus won't make the data available until after you open the stream and relinquish control of the run loop. – dgatwood Dec 28 '16 at 11:46