NSURLConnection sendSynchronousRequest doesn't fail on empty replies

Originator:nick.barkas
Number:rdar://13035252 Date Originated:17-Jan-2013 03:26 PM
Status:Open Resolved:
Product:Mac OS X SDK Product Version:10.8.2
Classification:Serious Bug Reproducible:Always
 
Summary:

When using -[NSURLConnection sendSynchronousRequest:returningResponse:error] to send a request to an HTTP server that closes the connection without replying, it returns a non-nil NSData return value, does not set the passed in error, and sets a passed in NSHTTPURLResponse to have a 200 status code. Therefore it is not possible to detect if a request to an HTTP server simply responded with a minimal successful response (i.e. only the status line "HTTP/1.1 200 OK<CRLF><CRLF>" or the server has dropped the connection without responding, possibly due to crashing, which should not in most cases be considered a success.

Steps to Reproduce:

Use -[NSURLConnection sendSynchronousRequest:returningResponse:error] to send an HTTP request to a server that receives requests but closes the connection without replying.

Expected Results:

-[NSURLConnection sendSynchronousRequest:returningResponse:error] returning nil and setting the passed in NSError parameter to a descriptive error.

The curl command line program, for example, exits with a failure status and prints the error message "curl: (52) Empty reply from server" when it is used to make requests against a server that drops connections in this way.

Actual Results:

-[NSURLConnection sendSynchronousRequest:returningResponse:error] returns an NSData object (with zero length) and sets the statusCode property of the passed in NSURLHTTPResponse to 200.

Regression:

I have not tried on any other versions of OS X, nor on iOS.

Notes:

I've attached a simple program (upload.m) that sends a GET request to the URL specified on the command line.  It can be compiled, then run against a simple python server that disconnects upon receiving requests as follows:

    python -c 'import BaseHTTPServer; h=BaseHTTPServer.BaseHTTPRequestHandler; h.do_GET=lambda x: None; BaseHTTPServer.HTTPServer(("127.0.0.1", 8080), h).serve_forever()' &
    clang -framework Foundation -o upload upload.m
    ./upload http://localhost:8080

Comments

Closed as duplicate of rdar://7550819

By nick.barkas at Feb. 2, 2013, 8:09 p.m. (reply...)

Example program attached to original radar

#import <Foundation/Foundation.h>

int main(int argc, char **argv) {
    if (argc != 2) {
        NSLog(@"Usage: %s <url>", argv[0]);
    }

    NSURL *url = [NSURL URLWithString:[NSString stringWithCString:argv[1]
                             encoding:NSUTF8StringEncoding]];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setHTTPMethod:@"GET"];

    NSHTTPURLResponse *response = nil;
    NSError *error = nil;
    NSData *result = [NSURLConnection sendSynchronousRequest:request
                                           returningResponse:&response
                                                       error:&error];

    if (result != nil) {
        NSLog(@"status code: %ld", [response statusCode]);
        NSLog(@"headers: %@", [response allHeaderFields]);
        NSLog(@"result size: %lu", [result length]);
    } else {
        NSLog(@"error is: %@", error);
    }

    return 0;
}
By nick.barkas at Jan. 17, 2013, 8:32 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!