Software Engineer

I am a Software Engineer. I have a Bachelor (Honours) of Science in Information Technology from the University of Sunderland - Class of 2003. I have been developing software since 2001 when I was offered a role at CERN as part of their Technical Student Programme.

By 2016 I had grown really tired of the software industry and by the end of 2019 Apple killed whatever excitement I had left. I am not sure what the next 10 years will bring. What I do know is that my apettite to do work that is impactful has only grown bigger and stronger. Great people make me tick more than anything.

I am also tired.

How to trace and debug an iOS crash (Part 2)

Dead end

Having reached a dead end, decided to take a look at the client side in an effort to understand more about the request/response cycle.

First thing was to enable logging for the headers and body of both the request and the response.

    > GET /foo HTTP/1.1  
    > "Accept-Encoding" = gzip;  
    > "Accept-Language" = [languages];  
    > Range = "foo=0-10";  
    > "User-Agent" = "[App Bundle Id]/ (unknown, iPhone OS 4.3.3, iPad, Scale/1.000000)";

    < HTTP/1.1 200 OK  
    < Content-Type: plain/text  
    < X-pad: avoid browser bug  

Notice the “Content-Type: plain/text” (though the “X-pad: avoid browser bug” did look interesting on its own way).

QUESTION: How and why the content type of the response was changing from the expected “application/json”?

EVIDENCE

1. > GET /foo HTTP/1.1
2. < [empty body]
3. Response "Content-Type: plain/text" (Application Layer)

Back to basics

Continuing with the elimination process, it was the iPad’s turn this time, substituting with curl

    [curl] -> [AWS Load Balancer] -> [AWS EC2 Single instance)

In an effort to reproduce the request as sent by the iPad, failed to receive the “desired” response, instead the received response was the expected “application/json” one.

    curl -v -A "[App Bundle Id]/ (unknown, iPhone OS 4.3.3, iPad, Scale/1.000000)" -H "Accept:" -H "Accept-Encoding: gzip" -H "Accept-Language" = "[languages]" -H "Range: foo=0-10" www.domain.com/foo

Bare in mind that the request headers above were obtained using

    NSLog(@"%@", [request allHTTPHeaderFields])

With no access to the iOS source, it’s difficult to know if every header is indeed in the returned NSDictionary. Hence decided to bring back to the equation the iPad and go down to the Network Layer to see the raw data.

Dumping the tcp

    [iPad 4.3.3 WiFi] -> [Mac] -> [AWS Load Balancer] -> [AWS EC2 Single instance)

In order to trace the network traffic as sent from the iPad, all you need is to have your Mac connected to the same network and share that network connection from OS X.

    Apple -> System Preferences -> Internet Sharing  
    "Share your connection from: Ethernet"  
    "To computers using: Wi-Fi"  
    "Computer name: [computer name]"  

Connect the iPad to the Wi-Fi [computer name] and have tcpdump running.

    sudo tcpdump -i en0 -s 0 -B 524288 -w ~/Desktop/DumpFile01.pcap

Here is what the tcpdump revealed.

    > HEAD /foo HTTP/1.1
    > Host: [AWS Load Balancer]
    > User-Agent: [App Bundle Id]/ (unknown, iPhone OS 4.3.3, iPad, Scale/1.000000)
    > Accept-Encoding: gzip
    > Accept-Language: [languages]
    > Accept: */*
    > Cookie: [cookies]
    > Content-Length: 0
    > Connection: keep-alive

    > HTTP/1.1 200 OK
    > Date: [timestamp]
    > Server: [server]
    > Content-Range: foo=0-10/11
    > Connection: Keep-alive
    > Content-Type: text/plain
    > X-Pad: avoid browser bug

followed by

    > GET /foo HTTP/1.1
    > Host: [AWS Load Balancer]
    > User-Agent: [App Bundle Id]/ (unknown, iPhone OS 4.3.3, iPad, Scale/1.000000)
    > Accept-Encoding: gzip
    > Accept-Language: [languages]
    > Range: foo=0-10
    > Accept: */*
    > Cookie: [cookies]
    > Connection: keep-alive

    < HTTP/1.1 200 OK
    < Date: [timestamp]
    < Server: [server]
    < Content-Range: foo=0-10/11
    < Content-Type: application/json
    < Connection: Keep-alive
    < transfer-encoding: chunked

Indeed there is a “plain/text” response but this is coming from a HEAD request on the same URL. What follows is the “application/json” one to the GET.

QUESTION: If the response is coming back as expected at the network layer, why are responses getting mixed up at the application layer?

Could that be a threading issue? A race condition? Why is it happening only on the iPad 4.3.3?

To make sure that this wasn’t a race condition, put a breakpoint on the completionBlock of the HEAD request to check the response. The response was the expected one.

Checking the response from GET however, turned out to be the same one as the HEAD.

QUESTION: Why would iOS 4.3.3 return a seemingly cached response?

EVIDENCE

1. > GET /foo HTTP/1.1
2. < [empty body]
3. Response "Content-Type: plain/text" (Application Layer)
4. Response "Content-Type: application/json" (Network Layer)
5. Cached response on GET /foo (Client side)

While debugging the above, came across a neat trick on how to query an http server for its version

A third part will follow