locked
HTTPWebReponse incomplete...sometimes RRS feed

  • Question

  • User24866 posted

    I have a situation where I'm Creating a http request and response to a web api. The code works fine in dot net AND on the iOS simulator. But when I deploy it to the iPhone I'm getting incomplete responses some of the time (happens maybe 1 out of 5 times). It is a bit confusing because I have 30 buttons each one sends a different request. Some time they receive the entire response, sometimes they are incomplete. Even the same request might be fine once and then fail the next time and be fine the next.

    This does not occur in the iOs simulator, it works flawlessly every time. I tried increasing the timeout which helped a little but Im still failing once out of 5-10 tries. Is it possible this is a multithreading issue?

    This is the core method:

    public static string GetResponseAsString(this HttpWebResponse response) { if (response == null) throw new ArgumentNullException("response");

            Stream responseStream = response.GetResponseStream();
            if (responseStream == null) return null;
    
            using (var stream = new StreamReader(responseStream, Encoding.UTF8))
            {
                return stream.ReadToEnd();
            }
        }
    

    This method call the previous method:

        public string Export(int activityId, bool detailedHistory, bool original)
        {
            string url = BuildExportUrl(activityId, detailedHistory, original);
            var request = HttpUtils.CreateRequest(url, session.Cookies);
            request.Timeout = 100000000; // :-)
            var response = (HttpWebResponse)request.GetResponse();
            return response.GetResponseAsString();
        }
    

    This is at the top of the call stack:

            var svc = new ActivityService(session);
            var tcx = svc.Export(activityId);
            ParsedResult = LapAnalyzer.AnalyzeFile(tcx); <-- fails here when an attempt is made to parse the xml. The error is always Unexpected End Of File.
    

    Im sure there is a simple fix but its driving me crazy.

    Thanks, Ron

    Thursday, October 10, 2013 10:45 PM

All replies

  • User24866 posted

    I stand corrected it does happen in the simulator as well.

    Ron

    Thursday, October 10, 2013 11:03 PM
  • User14533 posted

    I am experiencing similar behavior with an intermittently incomplete response stream when downloading large files. This only occurs on iOS. I am unable to repro it on Android using the same exact code from a C# library project that is shared between our iOS and Android apps.

    Like you, this only repro'd at first for me on an actual device. And, it only repro'd on a heavily used wifi network. When everyone else went home for the day, it temporarily stopped reproing.

    When I tried it on the simulator I was initially unable to repro until I switched from Ethernet to wifi, and even then it wouldn't repro until I unplugged the power from my MacBook and danced around the room with it while downloading the large file. It repro'd pretty consistently once I discovered this special technique.

    Then I discovered that I could also repro by turning off wifi on my MacBook during the download, or by running on Ethernet with wifi off and unplugging the Ethernet cable during the download. The only difference between this and the "real" bug is that turning off network connectivity took up to a minute of waiting before the problem occurred, while the original issue would happen immediately (at some random point during the download).

    The problem is that responseStream.Read() is returning 0 which is supposed to indicate that the end of the stream has been (successfully) reached. However, when this bug occurs, the cumulative offset into the stream is less than the response.ContentLength that we expected to receive. When everything goes well, those two numbers are the same.

    When running the exact same code on Windows and trying to simulate the same failure conditions, instead of just returning 0, calls to responseStream.Read() result in an IOException with the message "Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host." It's possible that my repro attempts on Windows aren't an accurate simulation of what's happening on iOS, but my theory is currently that there is a bug (or missing behavior) in the iOS implementation of Read() where it should be throwing an IOException but is instead returning a "successful" end-of-stream indication.

    To further confirm this theory, I tried downloading the large file from an actual iOS device and then using iOS 7's swipe-up control center to either disable wifi (when downloading from a local-only server) or turn on airplane mode, and they both resulted in the same behavior of silently "succeeding" in reading to the (incomplete) end of the stream rather than throwing an IOException.

    Here is my test code:

        var uri = new Uri("http://some-host/some-large-file.png");
    
        var request = WebRequest.Create(uri);
    
        using (var response = (HttpWebResponse)request.GetResponse())
        {
            if (response.StatusCode == HttpStatusCode.OK)
            {
                string fileName = GetContentDispositionFileName(response);
    
                using (var fileStream = File.OpenWrite(fileName))
                {
                    using (var responseStream = response.GetResponseStream())
                    {
                        var buffer = new byte[1024];
    
                        int bytesRead;
                        int offset = 0;
    
                        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            fileStream.Write(buffer, 0, bytesRead);
                            offset += bytesRead;
    
                            // only used to simplify bug repro on other platforms,
                            // not needed for the actual bug
                            Thread.Sleep(100);
                        }
    
                        if (offset != response.ContentLength)
                        {
                            throw new ApplicationException(
                                string.Format("Only downloaded {0} of {1} bytes", 
                                offset, response.ContentLength));
                        }
                    }
                }
            }
        }
    
    Thursday, October 24, 2013 1:05 AM
  • User14533 posted

    It turns out this also repros on Android when I use the airplane-mode technique. So this is a bug in the core Mono library shared by both iOS and Android.

    Thursday, October 24, 2013 7:21 PM
  • User14533 posted

    I reported these as bugs.

    iOS: https://bugzilla.xamarin.com/show_bug.cgi?id=15665

    Android: https://bugzilla.xamarin.com/show_bug.cgi?id=15666

    Thursday, October 24, 2013 8:02 PM
  • User76306 posted

    Does anybody know whether there is an update for this issue? I'm still getting no exception in some cases, just silently get no/incomplete data from response stream.

    Tuesday, June 14, 2016 9:51 AM
  • User166013 posted

    Same here. Simple string Content is not read entirely. Using this handler.

    var handler =new HttpClientHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip };

    Occurance seems to be completely random. Identical Requests (and responses) sometimes fail and sometimes succeed.

    Both on Simulator and Device.

    Friday, July 1, 2016 10:28 AM