Code Monkey home page Code Monkey logo

cocoaspdy's Introduction

CocoaSPDY

A SPDY/3.1 framework for iOS and Mac OS X

Branch Build Code Coverage
master Build Status Coverage Status
develop Build Status Coverage Status

The SPDY protocol

The short version is that SPDY can make your HTTP requests faster. Sometimes a lot faster. For more details, see the following:

http://www.chromium.org/spdy/spdy-whitepaper
http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1

SPDY was originally designed at Google as an experimental successor to HTTP. It's a binary protocol (rather than human-readable, like HTTP), but is fully compatible with HTTP. In fact, current draft work on HTTP/2.0 is largely based on the SPDY protocol and its real-world success.

In order to make HTTP requests go faster SPDY makes several improvements:

The first, and arguably most important, is request multiplexing. Rather than sending one request at a time over one TCP connection, SPDY can issue many requests simultaneously over a single TCP session and handle responses in any order, as soon as they're available.

Second, SPDY compresses both request and response headers. Headers are often nearly identical to each other across requests, generally contain lots of duplicated text, and can be quite large. This makes them an ideal candidate for compression.1

Finally, SPDY introduces server push.2 This can allow a server to push content that the client doesn't know it needs yet. Such content can range from additional assets like styles and images, to notifications about realtime events.

  1. Please see the note below about the CRIME attack.
  2. Not currently supported in this framework, but coming soon.

Getting Started

The SPDY framework is designed to work seamlessly with your existing apps and projects. If you are using the NSURL stack to issue requests (or any library that provides an abstraction over it, like AFNetworking), you can simply add the SPDY framework bundle to your project, link it to your targets, and enable the protocol.

The framework contains a multi-architecture/multi-platform ("fat") binary that supports versions of iOS 6 and above, and OS X Lion and above, as well as all hardware capable of running those operating systems. When you distribute your application, the size of the included binary will be dramatically reduced, provided you have code stripping enabled.

Enabling SPDY

To use the SPDY framework you'll need to link CFNetwork.framework and libz.dylib in your project. This can be done in the "Link Binary with Libraries" section under "Build Phases" for your compilation target.

The way you enable SPDY in your application will be slightly different depending on whether you are using NSURLConnection or NSURLSession to manage your HTTP calls. In order to cause requests issued via the NSURLConnection stack to be carried over SPDY, you'll make a method call to specify one or more origins (protocol-host-port tuple) to be handled by SPDY:

#import <SPDY/SPDYProtocol.h>
...
[SPDYURLConnectionProtocol registerOrigin:@"https://api.twitter.com:443"];

Note that origins containing "http" vs. "https" are distinct from each other, will be handled by separate SPDY sessions, and must be registered independently. Only sessions for origins containing "https" will be encrypted with TLS.

For NSURLSession, you can configure sessions to use SPDY via NSURLSessionConfiguration:

#import <SPDY/SPDYProtocol.h>
...
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.protocolClasses = @[[SPDYURLSessionProtocol class]];

You can freely use either or both methods, and existing SPDY sessions will be shared across both networking stacks. If you do use the former approach, note that registered origins will also be handled by SPDY with the default NSURLSession.

Either of the above one-liners is all you need to do to shift HTTP requests transparently over to SPDY. Of course you still need a server that speaks SPDY! Some possibilities are:

A note on NPN

Most existing SPDY implementations use a TLS extension called Next Protocol Implementation (NPN) to negotiate SPDY instead of HTTP. Unfortunately, this extension isn't supported by Secure Transport (Apple's TLS implementation), and so in order to use SPDY in your application, you'll either need to issue requests to a server that's configured to speak SPDY on a dedicated port, or use a server that's smart enough to examine the incoming request and determine whether the connection will be SPDY or HTTP based on what it looks like. At Twitter we do the latter, but the former solution may be simpler for most applications.

In order to aid with protocol inference, this SPDY implementation includes a non-standard settings id at index 0: SETTINGS_MINOR_VERSION. This is necessary to differentiate between SPDY/3 and SPDY/3.1 connections that were not negotiated with NPN, since only the major version is included in the frame header. Because not all servers may support this particular setting, sending it can be disabled at runtime through protocol configuration.

Implementation Notes

CRIME attack

The CRIME attack is a plaintext injection technique that exploits the fact that information can be inferred from compressed content length to potentially reveal the contents of an encrypted stream. This is a serious issue for browsers, which are subject to hijacks that may allow an attacker to issue an arbitrary number of requests with known plaintext header content and observe the resulting effect on compression.

In the context of an application that doesn't issue arbitrary requests, this is less likely to be an issue. However, before you ship a project with header compression enabled, you should understand the details of this attack and whether your application could be vulnerable.

Building the Framework Yourself

If you wish to compile the framework yourself, the process is fairly straightforward, and the build process should just work out of the box in Xcode. However, there are still a couple of things to note.

Prior to Xcode 5, if you wanted to compile the framework to a dual-platform binary (as in the distribution version), you were required to set 'iOS Device' as your platform target for the framework. This was due to a quirk in the Xcode build process that would otherwise exclude some (but not all) versions of the ARM architecture from the final binary. With the release of Xcode 5, any platform target should result in the same final universal binary (the setting is essentially ignored).

To create this binary, the build process actually depends on several static library targets and uses lipo to combine them.

Getting involved and Future work

We are always looking for people to get involved with the project.

In the near future, we will be working on:

Adopters

Please feel free to send us a pull request to add yourself to this list (bonus points to link to a tweet).

Problems?

If you find any issues please report them or better, send a pull request.

Authors

License

Copyright 2014 Twitter, Inc. and other contributors.

Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0

cocoaspdy's People

Contributors

caniszczyk avatar carsonmcdonald avatar chobits avatar cpg avatar dkhamsing avatar goaway avatar kgoodier avatar ladd avatar lingmingyb avatar nsprogrammer avatar patrickyevsukov avatar seivan avatar summerwind avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cocoaspdy's Issues

Support SPDY Draft 2 ?

Hello

Is CoCoa SPDY support Draft 2 Protocol ? I saw on the README that this Library support 3.1 , but have no ideal about older version .

Thanks

Note the use of custom HTTP status codes

We use the SPDY proxy server to define some custom HTTP status codes such as 800. But CocoaSPDY will throw an error. Here we have a better way to deal with it? Here is my code in "SPDYStream.m":

- (void)didReceiveResponse:(NSDictionary *)headers
{
    _receivedReply = YES;

    NSInteger statusCode = [headers[@":status"] intValue];

    //by rex 我们浏览器的自定义状态码是8XX
    //    if (statusCode < 100 || statusCode > 599) {
    if (statusCode < 100 || statusCode > 1000) {
        NSDictionary *info = @{ NSLocalizedDescriptionKey: @"invalid http response code" };
        NSError *error = [[NSError alloc] initWithDomain:NSURLErrorDomain
                                             code:NSURLErrorBadServerResponse
                                         userInfo:info];
        [self closeWithError:error];
        return;
    }

Consider breaking up large data sends to prevent priority inversion

In SPDYSession, in _sendData, the entire input stream is sent in a tight loop, assuming:

  1. The send window never closes
  2. The input stream supplies data

It's possible that a large upload on a slow network will block higher-priority requests that come in after the data upload has started. By breaking up large uploads into multiple data frames and processing any higher-priority operations in between, this priority inversion may be avoided.

the host should is host:port

In -allSPDYHeader of NSURLRequest + SPDYURLRequest.m.

  1. - NSMutableDictionary *spdyHeaders = [[NSMutableDictionary alloc] initWithDictionary:@{
  2. - @":method" : self.HTTPMethod,
  3. - @":path" : path,
  4. - @":version" : @"HTTP/1.1",
  5. - @":host" : url.host,
  6. - @":scheme" : url.scheme
  7. - }];

the host should is host:port。

(http://dev.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3#TOC-3.2.1-Request)
":host" - the hostport (See RFC1738) portion of the URL for this request (e.g. "www.google.com:1234"). This header is the same as the HTTP 'Host' header.

Configuring a server to accept SPDY requests

We have built a server at Amahi for our Amahi iOS app. The server supports NPN over SSL which has been implemented using the Amahi SPDY library. All other services have been enabled to communicate with our server using SPDY via NPN. Except the iOS app which still uses httpv1.1. We now want to use CocoaSPDY in our iOS app. We understand that CocoaSPDY does not support NPN. But due to constraints in the system, we cannot dedicate another port just for spdy requests from the iOS app.

The readme suggests that we "use a server that's smart enough to examine the incoming request and determine whether the connection will be SPDY or HTTP based on what it looks like".

I am looking for a way to build this "smart server" that can work without changing the current framework so as not to disrupt the server's interaction with other apps.

iOS 7.1.2 upload file failure

warning :using HTTPBodyStream on a SPDY request is subject to a potentially fatal CFNetwork

when upload file

iOS 9+ not call canonicalRequestForRequest even canInitWithRequest function return yes
but
iOS 7+ call canonicalRequestForRequest when canInitWithRequest function return yes,

Compatibility with cloudflare's SPDY implementation

Hello there,

Thanks a lot for sharing CocoaSPDY!
I'm having some troubles using the library (I'm having the same trace that issue #21 - Unexpected end of stream). On the server side, my APIs are hosted on Heroku, behind Cloudflare (with SPDY enabled - everything looks green but "HTTP Traffic Allowed" on http://spdycheck.org).
Is there a known hack or I should let it go?
Regards,

Ludovic

Why not use NSMutableURLRequest's HTTPBodyStream?

Hey @goaway, can you explain the warning in SPDYStream.m?

} else if (_request.HTTPBodyStream) {
    SPDY_WARNING(@"using HTTPBodyStream on a SPDY request is subject to a potentially fatal CFNetwork bug");
    _dataStream = _request.HTTPBodyStream;
}

a very easy sample. Crash after add SPDY.

a very easy sample, only send the same 10 requests on a tcp session. Crash stack:

  • thread #6: tid = 0x2a03, 0x3a4e3212 libsystem_c.dylibmemcpy$VARIANT$Swift + 524, queue = 'com.apple.CFURLCACHE_work_queue, stop reason = EXC_BAD_ACCESS (code=1, address=0x78c1310) frame #0: 0x3a4e3212 libsystem_c.dylibmemcpy$VARIANT$Swift + 524
    frame #1: 0x322dc57c CoreFoundationCFDataReplaceBytes + 564 frame #2: 0x322e9dba CoreFoundationCFDataAppendBytes + 86
    frame #3: 0x3203a678 CFNetworkCopyAllDataFromDataArray(__CFArray const*) + 108 frame #4: 0x3203abee CFNetwork__CFURLCache::ExecuteSQLInsert(CFCachedURLResponse const, _CFString const, CFURLRequest const) + 374
    frame #5: 0x32038ec6 CFNetwork__CFURLCache::AddCachedResponseForRequest(__CFURLCacheNode_, _CFCachedURLResponse const_, _CFURLRequest const_) + 62 frame #6: 0x32038d1c CFNetwork__CFURLCache::ProcessCacheTasks0(bool) + 144
    frame #7: 0x32038c80 CFNetwork__CFURLCache::ProcessCacheTasks(bool) + 36 frame #8: 0x32038b54 CFNetwork__CFURLCache::_CFURLCacheTimerCallback0() + 284
    frame #9: 0x32038a2c CFNetwork__CFURLCache::_CFURLCacheTimerCallback(void*) + 32 frame #10: 0x3a4a148e libdispatch.dylib_dispatch_source_invoke + 258
    frame #11: 0x3a4a3afc libdispatch.dylib_dispatch_queue_drain + 80 frame #12: 0x3a4a167c libdispatch.dylib_dispatch_queue_invoke + 44
    frame #13: 0x3a4a4612 libdispatch.dylib_dispatch_root_queue_drain + 210 frame #14: 0x3a4a47d8 libdispatch.dylib_dispatch_worker_thread2 + 92
    frame #15: 0x3a4c87f0 libsystem_c.dylib`_pthread_wqthread + 360

ViewController.m is very sample.

  • (void)viewDidLoad
    {
    [super viewDidLoad];

    NSLog(@"regsiter --- ---");

    //NSString *reginfo = [NSString stringWithFormat: @"http://%@:%d", @"192.168.1.2", 80];
    //[SPDYURLConnectionProtocol registerOrigin: reginfo];

    NSString *reginfo = [NSString stringWithFormat: @"http://%@:%d", @"192.168.1.3", 80];
    [SPDYURLConnectionProtocol registerOrigin: reginfo];

    NSString *url = [NSString stringWithFormat:@"http://192.168.1.2:80/tps/i1/T1H4e7Fn8gXXaGwNsc-640-1096.jpg"];

    for(int i=0; i<10; i++) {
    SpdyClient * client = [[SpdyClient alloc] init];
    client.request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:url]];

        client.done = NO;
        [client.request setValue: @"spdy" forHTTPHeaderField: @"x_spdy_request"];
        [client.request setValue: @"www.test.com" forHTTPHeaderField: @"host"];
    
        NSURLConnection *conn=[[NSURLConnection alloc]  initWithRequest:client.request delegate:client];
    
        if (conn) {
            client.receiveData = [[NSMutableData alloc] init];
        }else {
        }
    

    }

    // Do any additional setup after loading the view, typically from a nib.
    }

"allSPDYHeaderFields" get path error

I try to use CocoaSPDY visit our SPDY Proxy Server in my QQ Browser,meet a bug:

Visit http://m.sohu.com/n/452167131/?wscrid=15084_2,get a 301 redirect,the reason is that we have a error path:'/n/452167131?wscrid=15084_2',lost '/' when we use 'url.path'.

- (NSDictionary *)allSPDYHeaderFields
{
    NSDictionary *httpHeaders = self.allHTTPHeaderFields;
    NSURL *url = self.URL;

    static NSSet *invalidKeys;
    static NSSet *reservedKeys;
    static dispatch_once_t initialized;
    dispatch_once(&initialized, ^{
        invalidKeys = [[NSSet alloc] initWithObjects:
            @"connection", @"keep-alive", @"proxy-connection", @"transfer-encoding", nil
        ];

        reservedKeys = [[NSSet alloc] initWithObjects:
            @"method", @"path", @"version", @"host", @"scheme", nil
        ];
    });

    //----by rex----begin
    //Error:
    //Visit http://m.sohu.com/n/452167131/?wscrid=15084_2,get a 301 redirect,
    //the reason is that we have a error path:'/n/452167131?wscrid=15084_2',lost '/'
    //when we use 'url.path'.
    //
    //Reason:
    //Apple doc for 'url.path': If the path has a trailing slash, it is stripped.
    //
    //Solution:
    //http://markmail.org/message/cigyetgyjcvwsyx5#query:+page:1+mid:g4pmkeourikefc3p+state:results
    //NSString* s = @"http://example.com/path/to/id%3D8528/" ;
    //    NSLog(@"       given: %@", s) ;
    //    NSURL* url = [NSURL URLWithString:s] ;
    //    NSString* cocoaPath = [url path] ;
    //    NSString* cfPath = (NSString*)CFBridgingRelease(CFURLCopyPath((CFURLRef)url));
    //    NSString* cfstrictPath = (NSString*)CFBridgingRelease(CFURLCopyStrictPath((CFURLRef)url, NULL)) ;
    //    NSLog(@"   cocoaPath: %@", cocoaPath) ;
    //    NSLog(@"      cfPath: %@", cfPath) ;
    //    NSLog(@"cfstrictPath: %@", cfstrictPath) ;
    //
    //Result:
    //given: http://example.com/path/to/id%3D8528/
    //cocoaPath: /path/to/id=8528
    //cfPath: /path/to/id%3D8528/
    //cfstrictPath: path/to/id%3D8528/
    //


//    NSString *escapedPath = CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(
//            kCFAllocatorDefault,
//            (__bridge CFStringRef)url.path,
//            NULL,
//            CFSTR("?"),
//            kCFStringEncodingUTF8));

//    NSMutableString *path = [[NSMutableString alloc] initWithString:escapedPath];

    NSMutableString *path = [[NSMutableString alloc] initWithString:(NSString*)CFBridgingRelease(CFURLCopyPath((CFURLRef)url))];
    //----end----


    NSString *query = url.query;
    if (query) {
        [path appendFormat:@"?%@", query];
    }

    NSString *fragment = url.fragment;
    if (fragment) {
        [path appendFormat:@"#%@", fragment];
    }
......

Unable to upload files more than 65536 bytes

Hello,

We've started discussion here #85, but there was no answer so I decided to open an issue.

There is a function:

(void)didReadWindowUpdateFrame:(SPDYWindowUpdateFrame )windowUpdateFrame frameDecoder:(SPDYFrameDecoder *)frameDecoder
{
/*

SPDY WINDOW_UPDATE frame processing requirements: *
Receivers of a WINDOW_UPDATE that cause the window size to exceed 2^31
must send a RST_STREAM with the status code FLOW_CONTROL_ERROR. *
Sender should ignore all WINDOW_UPDATE frames associated with a stream
after sending the last frame for the stream. */
SPDYStreamId streamId = windowUpdateFrame.streamId;
SPDY_DEBUG(@"received WINDOW_UPDATE.%u (+%lu)", streamId, (unsigned long)windowUpdateFrame.deltaWindowSize);

if (streamId == kSPDYSessionStreamId) {
// Check for numerical overflow
if (_sessionSendWindowSize > INT32_MAX - windowUpdateFrame.deltaWindowSize) {
[self _closeWithStatus:SPDY_SESSION_PROTOCOL_ERROR];
return;
}

_sessionSendWindowSize += windowUpdateFrame.deltaWindowSize;
for (SPDYStream *stream in _activeStreams) {
    [self _sendData:stream];
    if (_sessionSendWindowSize == 0) break;
}

return;
}

// Ignore frames for non-existent or half-closed streams
SPDYStream *stream = _activeStreams[streamId];
if (!stream || stream.localSideClosed) {
return;
}

// Check for numerical overflow
if (stream.sendWindowSize > INT32_MAX - windowUpdateFrame.deltaWindowSize) {
[self _sendRstStream:SPDY_STREAM_FLOW_CONTROL_ERROR streamId:streamId];
return;
}

stream.sendWindowSize += windowUpdateFrame.deltaWindowSize;
[self _sendData:stream];
}

if streamId is eqal to kSPDYSessionStreamId then _sessionSendWindowSize should be increased, but if not, stream.sendWindowSize should be increased instead. So only one sendWindowSize will be increased, not the both.

In _sendData:(SPDYStream *)stream function both of sendWindowSize were decreased at the same time:

_sessionSendWindowSize -= bytesSent;
stream.sendWindowSize -= bytesSent;

and in case of bytesSent equals 65536 bytes, they both equal 0.

Upon next call to the _sendData this line will always return 0:

uint32_t sendWindowSize = MIN(_sessionSendWindowSize, stream.sendWindowSize);

because only one sendWindowSize was increased in didReadWindowUpdateFrame.

So, a file with size more than 65536 bytes will never send.

Use Spdy to speedy the ios app's request delay, but the result is not very nice to me.

the test result as followed is one url test, i am looking forward some person to give me some suggestions to solve the question.

the test Method is: the same devices(nearly 2,000 devices), 50%'s probability to use common http request when app startup, and 50%'s probability to use spdy requests.

/circle_getUserHeader.html,
WIFI_IPOD4,1 260/388 171ms/213ms (-24.31%)
WIFI_IPHONE8,2 1912/726 128ms/108ms (15.99%)
WIFI_IPHONE8,1 1911/1096 122ms/106ms (13.25%)
WIFI_IPHONE7,2 3574/1752 155ms/139ms (10.60%)
WIFI_IPHONE7,1 2399/1257 231ms/152ms (34.19%)
WIFI_IPHONE6,2 3804/3134 227ms/259ms (-13.75%)
WIFI_IPHONE6,1 571/174 189ms/152ms (19.64%)
WIFI_IPHONE5,2 880/693 237ms/161ms (32.12%)
WIFI_IPHONE4,1 1760/919 223ms/380ms (-70.53%)
WIFI_IPHONE3,1 838/213 348ms/333ms (4.46%)
WCDMA_IPHONE4,1 622/283 382ms/349ms (8.73%)
LTE_IPHONE8,2 392/150 436ms/303ms (30.47%)
LTE_IPHONE8,1 542/553 273ms/245ms (10.24%)
LTE_IPHONE7,2 4617/1857 211ms/206ms (2.71%)
LTE_IPHONE7,1 1111/888 205ms/231ms (-12.46%)
LTE_IPHONE6,2 1921/1255 314ms/212ms (32.38%)
HSDPA_IPHONE6,2 279/282 504ms/544ms (-7.80%)
EDGE_IPHONE3,1 164/250 1366ms/1053ms (22.91%)
CDMAEVDOREVA_IPHONE6,1 411/367 243ms/192ms (20.75%)
tReqs: 29774/17798 (37.41%)
tDelays: 256ms/250ms (2.20%)
delay: >0.8s >1.5s >4.0s >120.0s
spdy: (3.53%) (1.50%) (0.35%) (0.01%)
http: (3.81%) (1.81%) (0.49%) (0.00%)

Expose TCP connection time in metadata

The connectedMs field in the metadata is the time the request started relative to the time the connection started. Because we dispatch the first request into the socket and THEN do the connection, it is essentially 0 for the first request, and the total duration of that first request includes the TCP connection time.

Let's break out the TCP connection time into its own field. Maybe consider then subtracting that time from the duration of the first request.

Can CocoaSPDY support ASIHTTPRequest?

Hi, All,

In my project I have used ASIHTTPRequest for all the http requests, which are a lot.
Now I want to apply CocoaSPDY to this project.

Can CocoaSPDY catch all the ASIHTTPRequest request like it catching NSURLConnection's?

If not, is there a convenient way to change all ASIHTTPRequest to NSURLConnection?

Thank you very much in advance.

Support HTTP/2

We'd like CocoaSPDY to support HTTP/2, since it is the future and the use of SPDY will likely taper off over time. An implementation here would potentially come earlier than an official Apple version and could provide additional functionality, such as push requests and richer metadata. At present, there are no concrete plans for implementing HTTP/2 in CocoaSPDY, but if there is community interest please indicate it here.

Thread Safety Concerns

I wanted to open up a discussion about the approach to threading utilized in the library. CocoaSPDY is presently totally reliant on the socket being interacted with only through the NSURLConnectionLoader thread to guarantee its safety.

This has presented a number of challenges:

  1. In my test suite it requires acrobatics to gain control over the sockets and ensure that connections are torn down between test cases. Once I solved the issue of getting access to the sessions we face random crashes when socket activity occurs while a test is trying to shut down the session/socket from the main thread.
  2. Outside of a testing context we also have a desire to control the sockets independent of the NSURLProtocol interface.

In general I find GCD much easier to work with and reason about than runloops — particularly on threads I can’t access at will.

I have a patch set in development that introduced a GCD queue into the SPDYSocket class to ensure thread safety. This eliminates the need for CHECK_THREAD_SAFETY macros by providing strong guarantees of thread safety. Is this work you would consider merging?

Use NSURLRequest's allowsCellularAccess property

iOS 6 and OSX 10.8 added the 'allowsCellularAccess' property, which the app uses to tell the protocol whether the request is allowed to use cellular radio or not. CocoaSPDY does not consume this. SPDYSessionManager should. Found by code inspection, not verified.

Update the RTT (ping) periodically

Right now we do a ping at the very beginning and store that value for the life of the connection. We should update it "periodically", but first have to define exactly when & how often.

Fat Framework - no 64-bit sim support / not a real OS X framework

The SPDY framework target lipos together device arm7(s) & arm64, simulator x86 and Mac OS X x86_64 static targets. This has several consequences:

  • There is no 64-bit Simulator library. The x86_64 bit "slot" is taken up by the Mac OS X library.
  • The Mac OS X framework is not a valid framework. Static frameworks are not actually a real thing supported by Apple and Xcode. While we're pretending they are on iOS due to the lack of real frameworks we don't actually need to do that on OS X. OS X has real (dynamic) frameworks that are well supported by Xcode and the OS.

I'd suggest creating separate frameworks for iOS (which also includes 64 bit sim) and OSX (which would be a real dynamic 64 bit framework)

[Question] Is it possible to use CocoaSPDY without SSL?

I'm wondering if it's possible to use CocoaSPDY without SSL to reduce impact to our backend.

Line app integrates SPDY in plain mode according to their blog: http://tech.naver.jp/blog/?p=2381

We allow for non-encrypted connections. SPDY is usually used with TLS, but this slows down connection times and transfers–especially over mobile connections. Thus we decided to allow for non-encrypted connections over a mobile network.

We'd like to apply the same approach in our apps by integrating CocoaSPDY.

SystemConfiguration.framework might need to be manually added in project config

Hi,

I cloned the CocoaSPDY repo, made a few changes to accommodate my self-signed test server, and built the project, resulting in a framework. I then built a very simple iOS test app in Xcode 6.1.1, copied the framework into my project directory, and added the framework in "Link Binary with Libraries".

My project built and ran fine on the newer iOS simulators, but wouldn't successfully link when built targeting a iPhone 4S or one of the older simulators. It turned out I needed to manually add the 'SystemConfiguration' framework as well. After that it worked fine.

This isn't a bug report or a complaint about outstanding issues, but rather a suggestion that the instructions in the README mention the possible need to link the additional system framework. If nobody objects I can submit a pull request.

Thanks,
Austin

Is NSURLProtocol thread safe?

in test,every request startLoading in the same thread while i send request in the different thread, and why ?

Remove custom setTLSTrustEvaluator

Remove the + (void)setTLSTrustEvaluator:(id)evaluator; stuff and just use the NSURL provided mechanism for auth challenges. It's more complicated but unifies the interface better.

Can't compile the code after adding SPDY framework

Undefined symbols for architecture i386:
"_deflate", referenced from:
-[SPDYHeaderBlockCompressor deflate:availIn:outputBuffer:availOut:error:] in SPDY(SPDYHeaderBlockCompressor.o)
"_deflateEnd", referenced from:
-[SPDYHeaderBlockCompressor dealloc] in SPDY(SPDYHeaderBlockCompressor.o)
"deflateInit2", referenced from:
-[SPDYHeaderBlockCompressor initWithCompressionLevel:] in SPDY(SPDYHeaderBlockCompressor.o)
"_deflateSetDictionary", referenced from:
-[SPDYHeaderBlockCompressor initWithCompressionLevel:] in SPDY(SPDYHeaderBlockCompressor.o)
"_inflate", referenced from:
-[SPDYStream didLoadData:] in SPDY(SPDYStream.o)
-[SPDYHeaderBlockDecompressor inflate:availIn:outputBuffer:availOut:error:] in SPDY(SPDYHeaderBlockDecompressor.o)
"_inflateEnd", referenced from:
-[SPDYStream dealloc] in SPDY(SPDYStream.o)
-[SPDYHeaderBlockDecompressor dealloc] in SPDY(SPDYHeaderBlockDecompressor.o)
"inflateInit2", referenced from:
-[SPDYStream didReceiveResponse:] in SPDY(SPDYStream.o)
"inflateInit", referenced from:
-[SPDYHeaderBlockDecompressor init] in SPDY(SPDYHeaderBlockDecompressor.o)
"_inflateSetDictionary", referenced from:
-[SPDYHeaderBlockDecompressor inflate:availIn:outputBuffer:availOut:error:] in SPDY(SPDYHeaderBlockDecompressor.o)
"_kCFStreamPropertySSLPeerTrust", referenced from:
-[SPDYSocket _onTLSHandshakeSuccess] in SPDY(SPDYSocket.o)
"_kCFStreamPropertySSLSettings", referenced from:
-[SPDYSocket _tryTLSHandshake] in SPDY(SPDYSocket.o)
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1

  1. Another question. [SPDYURLConnectionProtocol registerOrigin:@"https://api.twitter.com:443"]; <- should it be server, port name only or complete URL?

An example project will be really helpful!

kSPDYOverride only read but never written

In file SPDYProtocol.m there is a kSPDYOverride constant that is never used except for reading:

In +[SPDYProtocol canInitWithRequest:]:

    NSString *scheme = request.URL.scheme.lowercaseString;
    if (![scheme isEqualToString:@"http"] && ![scheme isEqualToString:@"https"]) {
        return NO;
    }

    NSNumber *override = [SPDYProtocol propertyForKey:kSPDYOverride inRequest:request];
    return override == nil || override.boolValue;

But the key is never used in a setProperty:forKey:inRequest: (neither in this file, nor in any other file).

The method still works because it checks for a nil override, but the code that checks the key is unnecessary. The following should works as well:

NSString *scheme = request.URL.scheme.lowercaseString;
return [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"];

(By the way, impressive work. Congratulations)

SPDY for iOS with AFNetworking

I'm using AFNetworking2.1.0 and trying to add SPDY (with no success yet).
After calling registerOrigin, the requests always get Timed Out.

NSString *spdyURL = [NSString stringWithFormat:@"%@://%@:443",url.scheme, url.host];

[SPDYURLConnectionProtocol registerOrigin:spdyURL];

Note: I'm using Google App Engine, the baseURL I use is something like https://myapp.appspot.com/_ah and I was trying to register origin https://myapp.appsport.com:443

Proxy support?

I found CocoaSPDY don't use proxy setting of the system, can you add the proxy support?

CFNetwork SSLHandshake failed (-9807)

Hi,

My test spdy server is running with jetty, and i can visit it successfully by Chrome and the demo iphone app. When I applied CocoaSPDY to the demo app, I got the the logs below:

[iPhone App Error Log]

2014-02-10 18:34:22.481 demo[5262:70b] SPDY [WARNING] loaded DEBUG build of SPDY framework
2014-02-10 18:34:24.700 demo[5262:70b] SPDY [WARNING] loaded DEBUG build of SPDY framework
2014-02-10 18:34:28.246 demo[5262:3a03] SPDY [INFO] start loading https://10.68.145.89:8443/index.html
2014-02-10 18:34:28.248 demo[5262:3a03] SPDY [INFO] session connecting to <SPDYOrigin: 0x8d66ce0>
2014-02-10 18:34:28.249 demo[5262:3a03] SPDY [DEBUG] session using TLS
2014-02-10 18:34:28.250 demo[5262:3a03] SPDY [DEBUG] sent client SETTINGS
2014-02-10 18:34:28.250 demo[5262:3a03] SPDY [DEBUG] sent WINDOW_UPDATE.0 (+10420224)
2014-02-10 18:34:28.251 demo[5262:3a03] SPDY [DEBUG] sent SYN_STREAM.1!
2014-02-10 18:34:28.253 demo[5262:3a03] SPDY [DEBUG] socket connected to 10.68.145.89:8443
2014-02-10 18:34:28.291 demo[5262:3a03] CFNetwork SSLHandshake failed (-9807)
2014-02-10 18:34:28.293 demo[5262:3a03] SPDY [WARNING] session connection error: Error Domain=NSOSStatusErrorDomain Code=-9807 "The operation couldn’t be completed. (OSStatus error -9807.)"
2014-02-10 18:34:28.294 demo[5262:3a03] SPDY [INFO] session connection closed
2014-02-10 18:34:28.295 demo[5262:3a03] SPDY [INFO] stop loading https://10.68.145.89:8443/index.html

[Server Error Log]

19:08:54.252 [qtp2062722705-14 Selector0] DEBUG org.eclipse.jetty.io.nio - created SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=0,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0}-{@7d203b56 SSL NEED_UNWRAP i/o/u=-1/-1/-1 ishut=false oshut=false {EmptyAsyncConnection@26acb63d}}
19:08:54.256 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=179/0/0 ishut=false oshut=false {EmptyAsyncConnection@26acb63d} NEED_UNWRAP filled=179/179 flushed=0/0
19:08:54.258 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] unwrap OK NEED_TASK consumed=179 produced=0
19:08:54.259 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_TASK i/o/u=0/0/0 ishut=false oshut=false {EmptyAsyncConnection@26acb63d} NEED_TASK filled=0/0 flushed=0/0
19:08:54.357 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_WRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0} NEED_WRAP filled=0/0 flushed=0/0
19:08:54.357 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] wrap OK NEED_UNWRAP consumed=0 produced=1276
19:08:54.360 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0} NEED_UNWRAP filled=0/0 flushed=1276/0
19:08:54.362 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0} NEED_UNWRAP filled=0/0 flushed=0/0
19:08:54.364 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=1,open=true,ishut=false,oshut=false,rb=false,wb=false,w=true,i=0r}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0}}
19:08:54.365 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=0/0
19:08:54.367 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=1,open=true,ishut=true,oshut=false,rb=false,wb=false,w=true,i=0r}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=-14,l=0,c=0},r=0}}
19:08:54.368 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl -
javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
at sun.security.ssl.Alerts.getSSLException(Alerts.java:208) ~[?:1.7.0_51]
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1631) ~[?:1.7.0_51]
at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1599) ~[?:1.7.0_51]
at sun.security.ssl.SSLEngineImpl.closeInbound(SSLEngineImpl.java:1529) ~[?:1.7.0_51]
at org.eclipse.jetty.io.nio.SslConnection.closeInbound(SslConnection.java:435) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SslConnection.process(SslConnection.java:409) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SslConnection.process(SslConnection.java:295) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SslConnection.access$900(SslConnection.java:48) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SslConnection$SslEndPoint.fill(SslConnection.java:678) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.http.HttpParser.fill(HttpParser.java:1044) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:280) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:235) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SslConnection.handle(SslConnection.java:196) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:667) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:608) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:543) [jetty-all-server-8.1.14.v20131031.jar:8.1.14.v20131031]
at java.lang.Thread.run(Thread.java:744) [?:1.7.0_51]
19:08:54.374 [qtp2062722705-21] DEBUG org.eclipse.jetty.http.HttpParser - filled -1/0
19:08:54.375 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_WRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_WRAP filled=-1/0 flushed=0/0
19:08:54.375 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] wrap CLOSED NEED_UNWRAP consumed=0 produced=7
19:08:54.376 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - wrap CLOSE @7d203b56 SSL NEED_UNWRAP i/o/u=0/7/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} Status = CLOSED HandshakeStatus = NEED_UNWRAP
bytesConsumed = 0 bytesProduced = 7
19:08:54.377 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=7/0
19:08:54.379 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=1,open=true,ishut=true,oshut=false,rb=false,wb=false,w=true,i=0r}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.381 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - oshut SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=1,open=true,ishut=true,oshut=false,rb=false,wb=false,w=true,i=0r}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.382 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - close SCEP@32c81878{l(/10.68.145.89:61278)<->r(/10.68.145.89:8443),s=1,open=true,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0r}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.383 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=0/0
19:08:54.384 [qtp2062722705-14 Selector0] DEBUG org.eclipse.jetty.io.nio - destroyEndPoint SCEP@32c81878{l(null)<->r(0.0.0.0/0.0.0.0:8443),s=1,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0!}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.384 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(null)<->r(0.0.0.0/0.0.0.0:8443),s=1,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0!}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.384 [qtp2062722705-14 Selector0] DEBUG org.eclipse.jetty.server.AbstractHttpConnection - closed AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0
19:08:54.385 [qtp2062722705-21] DEBUG org.eclipse.jetty.server.AsyncHttpConnection - Disabled read interest while writing response SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}
19:08:54.386 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=0/0
19:08:54.387 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(null)<->r(0.0.0.0/0.0.0.0:8443),s=1,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0-}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.387 [qtp2062722705-21] DEBUG org.eclipse.jetty.server.AsyncHttpConnection - Disabled read interest while writing response SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}
19:08:54.388 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] handle @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} progress=true
19:08:54.389 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=0/0
19:08:54.390 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(null)<->r(0.0.0.0/0.0.0.0:8443),s=1,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0-}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.390 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} NEED_UNWRAP filled=-1/0 flushed=0/0
19:08:54.391 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ChannelEndPoint - ishut SCEP@32c81878{l(null)<->r(0.0.0.0/0.0.0.0:8443),s=1,open=false,ishut=true,oshut=true,rb=false,wb=false,w=true,i=0-}-{@7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}}
19:08:54.392 [qtp2062722705-21] DEBUG org.eclipse.jetty.server.AsyncHttpConnection - Disabled read interest while writing response SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0}
19:08:54.393 [qtp2062722705-21] DEBUG org.eclipse.jetty.io.nio.ssl - [Session-1, SSL_NULL_WITH_NULL_NULL] handle @7d203b56 SSL NEED_UNWRAP i/o/u=0/0/0 ishut=false oshut=false {AsyncHttpConnection@650a73bc,g=HttpGenerator{s=0,h=-1,b=-1,c=-1},p=HttpParser{s=0,l=0,c=0},r=0} progress=false

[Lib Version]
jetty and spdy api version: 8.1.14.v20131031
npn-boot version: 1.1.6.v20130911
jdk version: 1.7.0_51

Do you have any idea of the causes of this problem.
Thanks in advance.

A crash on make spdyHeaders

When we visit "http://wsq.discuz.qq.com/",we get a sub request "http:/"(NSURLConnecction + (BOOL)canHandleRequest:(NSURLRequest *)request; return YES,so this is a valid request),get a crash on [- (NSDictionary *)allSPDYHeaderFields] of NSURLRequest+SPDYURLRequest.m.
The reason is host is nil,causes crash to initialize NSMutableDictionary
Now I modify the code as follows:

NSMutableDictionary *spdyHeaders = [[NSMutableDictionary alloc] initWithDictionary:@{
         @":method"  : self.HTTPMethod ? self.HTTPMethod : @"GET",
         @":path"    : path ? path : @"/",
         @":version" : @"HTTP/1.1",
         @":host"    : url.host ? url.host : @"",
         @":scheme"  : url.scheme ? url.scheme : @"",
         }];

Data inconsistencies

the data post by _client didloadData different from received in didreceiveddata. Some people encountered ?
data print in didloadData .
streamid = 1 data <ffd8ffe0 00104a46 49460001 01010048 00480000 ffdb0043 .......

data print in DidreceivedData.
<a74fb4f5 f0aeae6b d26b963c 3d665a7b 2cd269dc ecebc979 95fa5acc f5f6eaab .......

Crash after add Framwork!

2014-01-07 16:01:01.202 myproject[92051:70b] SPDY [WARNING] loaded DEBUG build of SPDY framework
2014-01-07 16:01:01.264 myproject[92051:70b] regsiter --- ---
2014-01-07 16:01:01.265 myproject[92051:70b] SPDY [INFO] register origin: <SPDYOrigin: 0x109117bc0>
2014-01-07 16:01:01.265 myproject[92051:70b] SPDY [INFO] register origin: <SPDYOrigin: 0x109117f10>
2014-01-07 16:01:01.265 myproject[92051:f03] SPDY [DEBUG] origin registered: <SPDYOrigin: 0x109117bc0>
2014-01-07 16:01:01.266 myproject[92051:f03] SPDY [DEBUG] origin registered: <SPDYOrigin: 0x109117f10>
2014-01-07 16:01:01.283 myproject[92051:330b] SPDY [INFO] start loading http://119.167.151.250:80/tps/i1/T1H4e7Fn8gXXaGwNsc-640-1096.jpg
2014-01-07 16:01:01.285 myproject[92051:330b] SPDY [INFO] session connecting to <SPDYOrigin: 0x109214920>
2014-01-07 16:01:01.286 myproject[92051:330b] SPDY [DEBUG] sent client SETTINGS
2014-01-07 16:01:01.286 myproject[92051:330b] SPDY [DEBUG] sent WINDOW_UPDATE.0 (+10420224)
2014-01-07 16:01:01.287 myproject[92051:330b] -[NSURLRequest SPDYPriority]: unrecognized selector sent to instance 0x109358b70
2014-01-07 16:01:01.289 myproject[92051:330b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLRequest SPDYPriority]: unrecognized selector sent to instance 0x109358b70'
*** First throw call stack:
(
0 CoreFoundation 0x0000000101c49795 exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001019ac991 objc_exception_throw + 43
2 CoreFoundation 0x0000000101cdabad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x0000000101c3b09d __forwarding
+ 973
4 CoreFoundation 0x0000000101c3ac48 _CF_forwarding_prep_0 + 120
5 myproject 0x0000000100019677 -[SPDYStream initWithProtocol:dataDelegate:] + 375
6 myproject 0x0000000100013c67 -[SPDYSession issueRequest:] + 103
7 myproject 0x0000000100011d90 -[SPDYProtocol startLoading] + 544
8 Foundation 0x00000001015d519b -[NSBlockOperation main] + 75
9 Foundation 0x0000000101623844 -[__NSOperationInternal _start:] + 623
10 Foundation 0x000000010165a00c -[_NSCFURLProtocolBridgeWithTrampoline processEventQ] + 252
11 Foundation 0x000000010165a5e2 -[_NSCFURLProtocolBridgeWithTrampoline pushEvent:from:] + 174
12 Foundation 0x000000010165adec -[_NSCFURLProtocolBridge start] + 83
13 Foundation 0x000000010165bcbc bridgeStart + 72
14 CFNetwork 0x00000001001c5dd6 _ZN19URLProtocol_Classic28_protocolInterface_startLoadEPK20_CFCachedURLResponse + 74
15 CFNetwork 0x00000001001ebe73 ___ZN19URLConnectionLoader27_private_ScheduleOriginLoadEPK13_CFURLRequestPK20_CFCachedURLResponse_block_invoke_2 + 158
16 CFNetwork 0x00000001001eacea ___ZNK19URLConnectionLoader25withExistingProtocolAsyncEU13block_pointerFvP11URLProtocolE_block_invoke + 25
17 CFNetwork 0x0000000100225f74 ___ZNK17CoreSchedulingSet13_performAsyncEPKcU13block_pointerFvvE_block_invoke + 25
18 CoreFoundation 0x0000000101bf0114 CFArrayApplyFunction + 68
19 CFNetwork 0x0000000100155beb _ZN19RunloopBlockContext7performEv + 115
20 CFNetwork 0x0000000100155a31 _ZN17MultiplexerSource7performEv + 247
21 CFNetwork 0x0000000100155854 _ZN17MultiplexerSource8_performEPv + 72
22 CoreFoundation 0x0000000101bd8ec1 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
23 CoreFoundation 0x0000000101bd8792 CFRunLoopDoSources0 + 242
24 CoreFoundation 0x0000000101bf461f __CFRunLoopRun + 767
25 CoreFoundation 0x0000000101bf3f33 CFRunLoopRunSpecific + 467
26 Foundation 0x000000010156236c +[NSURLConnection(Loader) _resourceLoadLoop:] + 348
27 Foundation 0x00000001015b4e0f __NSThread__main
+ 1167
28 libsystem_pthread.dylib 0x00000001023b8899 _pthread_body + 138
29 libsystem_pthread.dylib 0x00000001023b872a _pthread_struct_init + 0
30 libsystem_pthread.dylib 0x00000001023bcfc9 thread_start + 13
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Unexpected end of stream

Hi,

First I want to thanks you for providing this library.

Our server is setup to use SPDY but anytime I try to call a webservice, I got an error.

Logs are :

SPDY [WARNING] loaded DEBUG build of SPDY framework
SPDY [INFO] register origin: <SPDYOrigin: 0xc488c70>
SPDY [DEBUG] origin registered: <SPDYOrigin: 0xc488c70>
SPDY [INFO] start loading https://XXXXXXXX/sts/SecurityTokenService/UT
SPDY [INFO] session connecting to <SPDYOrigin: 0xc7b1910>
SPDY [DEBUG] session using TLS
SPDY [DEBUG] sent client SETTINGS
SPDY [DEBUG] sent WINDOW_UPDATE.0 (+10420224)
SPDY [DEBUG] sent SYN_STREAM.1
SPDY [DEBUG] sent DATA.1! (1161)
SPDY [DEBUG] socket connected to XXXXXXX
SPDY [DEBUG] socket read0
SPDY [DEBUG] received DATA.1013478509 (165)
SPDY [DEBUG] sent RST_STREAM.1013478509
SPDY [DEBUG] socket scheduling read1
SPDY [WARNING] session connection error: Error Domain=SPDYSocketErrorDomain Code=6 "Unexpected end of stream." UserInfo=0xc79eb40 {NSLocalizedDescription=Unexpected end of stream.}
SPDY [INFO] session connection closed
SPDY [INFO] stop loading https://XXXXXXXX/sts/SecurityTokenService/UT

Do you have any idea of the reason or causes of this problem.

Thanks in advance.

Having trouble linking the "framework" in iOS app

Hey there, I've been trying for a while to get the lipo'd framework linking with my iOS app to try SPDY out with it.

I have created an example project showing how I'm trying to set it up, which is at https://github.com/danielctull-tests/SPDY-Linking-Test

My setup is as such:

  • I have my app project in git and added SPDY as a submodule
  • In my app's project, I have added the SPDY project as a sub-project
  • Add SPDY.framework to "Target Dependencies"
  • Add SPDY.framework to "Link Binary with Libraries"

(In my experience, libraries don't usually need step 3, you just link them and they'll build, but this framework does.)

I'm running into a problem that says:

clang: error: no such file or directory: '/Users/danielctull/Library/Developer/Xcode/DerivedData/SPDY_Linking_Test-ccbjivxaodzvgebftyllogvlhldk/Build/Products/Debug/SPDY/SPDY'

I've tried adding the location the SPDY.framework gets build to (Debug vs Debug-iphonesimulator) to the libraries and frameworks search paths in my app target's settings, but this doesn't help.

Unfortunately, while I've done a lot of work with normal static libraries and linking them etc, I'm not 100% how Xcode links, and where it expects to find, fake frameworks like this.

Any advice would be great.

How to run against localhost?

I'm trying to run this library against localhost, but I cannot get past the TLS handshake. I have tried the following:
The base case:

NSURL *url = [NSURL URLWithString:@"https://localhost:8888"];

    // USING NSURLSession defaultSessionConfiguration];
    NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
    config.protocolClasses = @[[SPDYURLSessionProtocol class]];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];

    NSURLRequest *req = [NSURLRequest requestWithURL:url];
    id task = [session dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error)

This as expected, fails the TLS handshake. So, I tried to avoid it with:

SPDYConfiguration *configuration = [SPDYConfiguration defaultConfiguration];
    NSMutableDictionary *tlsSettings = [NSMutableDictionary dictionary];
    [tlsSettings setObject:(NSNumber *)kCFBooleanFalse forKey:(NSString *)kCFStreamSSLValidatesCertificateChain];
    [configuration setValue:tlsSettings forKey:@"tlsSettings"];

    [SPDYURLConnectionProtocol setConfiguration:configuration];

This fails with:
2015-10-03 14:31:03.688 SimpleSPDYExample[7271:1288578] SPDY [ERROR] socket closing with error: Error Domain=SPDYSocketErrorDomain Code=6 "Unexpected end of stream." UserInfo={NSLocalizedDescription=Unexpected end of stream.}

Finally, I tried adding my certificate as a profile to the simulator (without the config code above), but this didn't help. If I go to safari in the simulator, and go to https://localhost:8888, it has an untrusted cert error. But after I added the cert as a root certificate on the simulator, there was no problem. But there was still a problem with the sample app with the code above.

Note: The above code works if I just run it over NSURLSession without the SPDY protocol by adding:

// This gets around the fact that the sample server running on the sample domain is using a self-signed certificate.
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler {
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]){
        NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
        completionHandler(NSURLSessionAuthChallengeUseCredential,credential);
    }

How can I successfully run against localhost without TLS errors?

ps. Here is my server code in node.js (very simple):

var spdy = require('spdy');
var fs = require('fs');

var options = {
  key: fs.readFileSync(__dirname + '/keys/key.pem'),
  cert: fs.readFileSync(__dirname + '/keys/cert.pem')
};

var server = spdy.createServer(options, function(req, res) {
  var message = "No SPDY for you!"
  if (req.isSpdy){
    message = "YAY! SPDY Works!"
  }
  res.end('hello world! ' + message);
});

server.listen(8888);

Thanks for any help you can give me.

Hangs on Google Cloud Storage

Why would the following code hang when the url points to google cloud storage (which supports SPDY) and not when using api.twitter.com for example?

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [SPDYURLConnectionProtocol registerOrigin:@"https://storage.googleapis.com:443"];
        NSString* url = @"https://storage.googleapis.com:443/exoweatherimg.appspot.com/blue/tile_z4/x8_y6.jpg";
        NSURLRequest* request = [NSURLRequest requestWithURL: [NSURL URLWithString: url]];
        NSError* error =nil;
        NSURLResponse* resp;
        NSData* imageData = [NSURLConnection sendSynchronousRequest:request returningResponse:&resp error:&error];
        NSLog(@"SPDY received data:%i", [imageData length]);
    });

wireshark capature find "SPDY: Inflation failed. Aborting. " why ?

like
353: Inflation failed. Aborting.

Frame 655: 648 bytes on wire (5184 bits), 648 bytes captured (5184 bits) on interface 0
Raw packet data
Internet Protocol Version 4, Src: 119.167.232.102, Dst: 10.25.51.220
Transmission Control Protocol, Src Port: 7777 (7777), Dst Port: 60292 (60292), Seq: 147267, Ack: 317, Len: 608
SPDY: SYN_REPLY, Stream: 1147 [Error: Header decompression failed]
1... .... .... .... = Control frame: Yes
.000 0000 0000 0011 = Version: 3
Type: SYN_REPLY (2)
Flags: 0x00
Length: 600
.000 0000 0000 0000 0000 0100 0111 1011 = Stream ID: 1147
Header block: 004a02b5fd0000000f000000083a76657273696f6e000000...
[Expert Info (Error/Undecoded): Inflation failed. Aborting.]
[Inflation failed. Aborting.]
[Severity level: Error]
[Group: Undecoded]

set window size 2^31-1,but send over 65536 data is timeout

Server set window size is 2^31-1 for speed , so server don't send window update, and setting feedback wind size。 in code , _initialSendWindowSize is update in SPDYSession.m , _sessionSendWindowSize not update, but sending data use MIN(_initialSendWindowSize,_sessionSendWindowSize)

NSURLConnection crash

Thread 0 Crashed:
0 CFNetwork 0x2d4c3388 HTTPParser::HTTPParser(CFAllocator const_, HTTPParserClient_, HTTPParser_) + 32
1 CFNetwork 0x2d4a5a56 HTTPMessage::commonInitialization(unsigned char, HTTPMessage const_) + 134
2 CFNetwork 0x2d4a61e0 HTTPMessage::HTTPMessage(HTTPMessage const_) + 84
3 CFNetwork 0x2d4a60e2 HTTPRequestMessage::HTTPRequestMessage(HTTPRequestMessage const_) + 14
4 CFNetwork 0x2d4a60a4 HTTPRequest::HTTPRequest(HTTPRequest const_) + 8
5 CFNetwork 0x2d4a604e URLRequest::initialize(URLRequest const_, unsigned char) + 354
6 CFNetwork 0x2d4a5ed2 _createRequestCopy(_CFAllocator const, CFURLRequest const, unsigned char) + 94
7 Foundation 0x2e1e166c createCFRequest + 36
8 Foundation 0x2e1e1166 -[NSURLConnectionInternalConnection initWithInfo:] + 94
9 Foundation 0x2e1e1002 -[NSURLConnection(Private) _initWithRequest:delegate:usesCache:maxContentLength:startImmediately:connectionProperties:] + 294
10 Foundation 0x2e23313a -[NSURLConnection initWithRequest:delegate:startImmediately:] + 50
11 MyAPP.app 0x00ce5966 0x1b000 + 13412710
12 libdispatch.dylib 0x38164d78 _dispatch_call_block_and_release + 8
13 libdispatch.dylib 0x38164d64 _dispatch_client_callout + 20
14 libdispatch.dylib 0x3816b7bc _dispatch_main_queue_callback_4CF$VARIANT$mp + 264
15 CoreFoundation 0x2d87381c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
+ 4
16 CoreFoundation 0x2d8720f0 __CFRunLoopRun + 1296
17 CoreFoundation 0x2d7dcce2 CFRunLoopRunSpecific + 518
18 CoreFoundation 0x2d7dcac6 CFRunLoopRunInMode + 102
19 GraphicsServices 0x324fd27e GSEventRunModal + 134
20 UIKit 0x3007ea3c UIApplicationMain + 1132
21 MyAPP.app 0x00020d4e 0x1b000 + 23886
22 MyAPP.app 0x00020c74 0x1b000 + 23668

A new app seems to crash and spdy relationship.
The above is a crash log。
Is there a way around this?

Request in NSURLConnection and UIWebView will lead to crash.

I send many requests with my custom NSURLConnection.After that I send many other same request in UIWebView. The result is crash!I found SPDYSocket is not thread-safe. And NSURLConnection and UIWebView will run in different threads.(NSURLConnectionLoader and WebCore CFNetwork)
How to fix?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.