* The BLIPConnection receivedRequest: delegate method now returns BOOL. If the method returns NO (or if the method isn't implemented in the delegate), that means it didn't handle the message at all; an error will be returned to the sender. default tip
authorJens Alfke <jens@mooseyard.com>
Fri Jul 24 14:06:28 2009 -0700 (2009-07-24)
changeset 635e4855a592ee
parent 62 8713f2d6a4c5
* The BLIPConnection receivedRequest: delegate method now returns BOOL. If the method returns NO (or if the method isn't implemented in the delegate), that means it didn't handle the message at all; an error will be returned to the sender.
* If the connection closes unexpectedly due to an error, then the auto-generated responses to pending requests will contain that error. This makes it easier to display a meaningful error message in the handler for the request.
BLIP/BLIPConnection.h
BLIP/BLIPConnection.m
BLIP/BLIPRequest.m
BLIP/BLIPTest.m
BLIP/Demo/BLIPEchoServer.m
     1.1 --- a/BLIP/BLIPConnection.h	Tue Jul 21 15:06:15 2009 -0700
     1.2 +++ b/BLIP/BLIPConnection.h	Fri Jul 24 14:06:28 2009 -0700
     1.3 @@ -66,11 +66,13 @@
     1.4  
     1.5  /** Called when a BLIPRequest is received from the peer, if there is no BLIPDispatcher
     1.6      rule to handle it.
     1.7 +    If the delegate wants to accept the request it should return YES; if it returns NO,
     1.8 +    a kBLIPError_NotFound error will be returned to the sender.
     1.9      The delegate should get the request's response object, fill in its data and properties
    1.10      or error property, and send it.
    1.11      If it doesn't explicitly send a response, a default empty one will be sent;
    1.12      to prevent this, call -deferResponse on the request if you want to send a response later. */
    1.13 -- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request;
    1.14 +- (BOOL) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request;
    1.15  
    1.16  /** Called when a BLIPResponse (to one of your requests) is received from the peer.
    1.17      This is called <i>after</i> the response object's onComplete target, if any, is invoked.*/
     2.1 --- a/BLIP/BLIPConnection.m	Tue Jul 21 15:06:15 2009 -0700
     2.2 +++ b/BLIP/BLIPConnection.m	Fri Jul 24 14:06:28 2009 -0700
     2.3 @@ -69,13 +69,14 @@
     2.4  }
     2.5  
     2.6  
     2.7 -- (void) _dispatchMetaRequest: (BLIPRequest*)request
     2.8 +- (BOOL) _dispatchMetaRequest: (BLIPRequest*)request
     2.9  {
    2.10      NSString* profile = request.profile;
    2.11 -    if( [profile isEqualToString: kBLIPProfile_Bye] )
    2.12 +    if( [profile isEqualToString: kBLIPProfile_Bye] ) {
    2.13          [self _handleCloseRequest: request];
    2.14 -    else
    2.15 -        [request respondWithErrorCode: kBLIPError_NotFound message: @"Unknown meta profile"];
    2.16 +        return YES;
    2.17 +    }
    2.18 +    return NO;
    2.19  }
    2.20  
    2.21  
    2.22 @@ -83,11 +84,19 @@
    2.23  {
    2.24      LogTo(BLIP,@"Received all of %@",request.descriptionWithProperties);
    2.25      @try{
    2.26 +        BOOL handled;
    2.27          if( request._flags & kBLIP_Meta )
    2.28 -            [self _dispatchMetaRequest: request];
    2.29 -        else if( ! [self.dispatcher dispatchMessage: request] )
    2.30 -            [self tellDelegate: @selector(connection:receivedRequest:) withObject: request];
    2.31 -        if( ! request.noReply && ! request.repliedTo ) {
    2.32 +            handled =[self _dispatchMetaRequest: request];
    2.33 +        else {
    2.34 +            handled = [self.dispatcher dispatchMessage: request];
    2.35 +            if (!handled && [_delegate respondsToSelector: @selector(connection:receivedRequest:)])
    2.36 +                handled = [_delegate connection: self receivedRequest: request];
    2.37 +        }
    2.38 +        
    2.39 +        if (!handled) {
    2.40 +            LogTo(BLIP,@"No handler found for incoming %@",request);
    2.41 +            [request respondWithErrorCode: kBLIPError_NotFound message: @"No handler was found"];
    2.42 +        } else if( ! request.noReply && ! request.repliedTo ) {
    2.43              LogTo(BLIP,@"Returning default empty response to %@",request);
    2.44              [request respondWithData: nil contentType: nil];
    2.45          }
     3.1 --- a/BLIP/BLIPRequest.m	Tue Jul 21 15:06:15 2009 -0700
     3.2 +++ b/BLIP/BLIPRequest.m	Fri Jul 24 14:06:28 2009 -0700
     3.3 @@ -271,13 +271,17 @@
     3.4  {
     3.5      [super _connectionClosed];
     3.6      if( !_isMine && !_complete ) {
     3.7 +        NSError *error = _connection.error;
     3.8 +        if (!error)
     3.9 +            error = BLIPMakeError(kBLIPError_Disconnected,
    3.10 +                                  @"Connection closed before response was received");
    3.11          // Change incoming response to an error:
    3.12          _isMutable = YES;
    3.13          [_properties autorelease];
    3.14          _properties = [_properties mutableCopy];
    3.15 -        [self _setError: BLIPMakeError(kBLIPError_Disconnected,
    3.16 -                                         @"Connection closed before response was received")];
    3.17 +        [self _setError: error];
    3.18          _isMutable = NO;
    3.19 +        
    3.20          self.complete = YES;    // Calls onComplete target
    3.21      }
    3.22  }
     4.1 --- a/BLIP/BLIPTest.m	Tue Jul 21 15:06:15 2009 -0700
     4.2 +++ b/BLIP/BLIPTest.m	Fri Jul 24 14:06:28 2009 -0700
     4.3 @@ -127,6 +127,18 @@
     4.4  {
     4.5      if( _conn.status==kTCP_Open || _conn.status==kTCP_Opening ) {
     4.6          if(_pending.count<100) {
     4.7 +            Log(@"** Sending a message that will fail to be handled...");
     4.8 +            BLIPRequest *q = [_conn requestWithBody: nil
     4.9 +                                         properties: $dict({@"Profile", @"BLIPTest/DontHandleMe"},
    4.10 +                                                           {@"User-Agent", @"BLIPConnectionTester"},
    4.11 +                                                           {@"Date", [[NSDate date] description]})];
    4.12 +            BLIPResponse *response = [q send];
    4.13 +            Assert(response);
    4.14 +            Assert(q.number>0);
    4.15 +            Assert(response.number==q.number);
    4.16 +            [_pending setObject: [NSNull null] forKey: $object(q.number)];
    4.17 +            response.onComplete = $target(self,responseArrived:);
    4.18 +            
    4.19              Log(@"** Sending another %i messages...", kNBatchedMessages);
    4.20              for( int i=0; i<kNBatchedMessages; i++ ) {
    4.21                  size_t size = random() % 32768;
    4.22 @@ -135,11 +147,12 @@
    4.23                  for( size_t i=0; i<size; i++ )
    4.24                      bytes[i] = i % 256;
    4.25                  
    4.26 -                BLIPRequest *q = [_conn requestWithBody: body
    4.27 -                                             properties: $dict({@"Content-Type", @"application/octet-stream"},
    4.28 -                                                               {@"User-Agent", @"BLIPConnectionTester"},
    4.29 -                                                               {@"Date", [[NSDate date] description]},
    4.30 -                                                               {@"Size",$sprintf(@"%u",size)})];
    4.31 +                q = [_conn requestWithBody: body
    4.32 +                                 properties: $dict({@"Profile", @"BLIPTest/EchoData"},
    4.33 +                                                   {@"Content-Type", @"application/octet-stream"},
    4.34 +                                                   {@"User-Agent", @"BLIPConnectionTester"},
    4.35 +                                                   {@"Date", [[NSDate date] description]},
    4.36 +                                                   {@"Size",$sprintf(@"%u",size)})];
    4.37                  Assert(q);
    4.38                  if( kUseCompression && (random()%2==1) )
    4.39                      q.compressed = YES;
    4.40 @@ -189,29 +202,35 @@
    4.41      [NSObject cancelPreviousPerformRequestsWithTarget: self];
    4.42      CFRunLoopStop(CFRunLoopGetCurrent());
    4.43  }
    4.44 -- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
    4.45 +- (BOOL) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
    4.46  {
    4.47      Log(@"***** %@ received %@",connection,request);
    4.48      [request respondWithData: request.body contentType: request.contentType];
    4.49 +    return YES;
    4.50  }
    4.51  
    4.52  - (void) connection: (BLIPConnection*)connection receivedResponse: (BLIPResponse*)response
    4.53  {
    4.54      Log(@"********** %@ received %@",connection,response);
    4.55 -    NSNumber *sizeObj = [_pending objectForKey: $object(response.number)];
    4.56 -
    4.57 -    if( response.error )
    4.58 -        Warn(@"Got error response: %@",response.error);
    4.59 -    else {
    4.60 -        NSData *body = response.body;
    4.61 -        size_t size = body.length;
    4.62 -        Assert(size<32768);
    4.63 -        const UInt8 *bytes = body.bytes;
    4.64 -        for( size_t i=0; i<size; i++ )
    4.65 -            AssertEq(bytes[i],i % 256);
    4.66 -        AssertEq(size,sizeObj.unsignedIntValue);
    4.67 +    id sizeObj = [_pending objectForKey: $object(response.number)];
    4.68 +    Assert(sizeObj);
    4.69 +    
    4.70 +    if (sizeObj == [NSNull null]) {
    4.71 +        AssertEqual(response.error.domain, BLIPErrorDomain);
    4.72 +        AssertEq(response.error.code, kBLIPError_NotFound);
    4.73 +    } else {
    4.74 +        if( response.error )
    4.75 +            Warn(@"Got error response: %@",response.error);
    4.76 +        else {
    4.77 +            NSData *body = response.body;
    4.78 +            size_t size = body.length;
    4.79 +            Assert(size<32768);
    4.80 +            const UInt8 *bytes = body.bytes;
    4.81 +            for( size_t i=0; i<size; i++ )
    4.82 +                AssertEq(bytes[i],i % 256);
    4.83 +            AssertEq(size,[sizeObj unsignedIntValue]);
    4.84 +        }
    4.85      }
    4.86 -    Assert(sizeObj);
    4.87      [_pending removeObjectForKey: $object(response.number)];
    4.88      Log(@"Now %u replies pending", _pending.count);
    4.89  }
    4.90 @@ -326,26 +345,35 @@
    4.91          Log(@"** %@ didClose", connection);
    4.92      [connection release];
    4.93  }
    4.94 -- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
    4.95 +- (BOOL) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
    4.96  {
    4.97      Log(@"***** %@ received %@",connection,request);
    4.98 -    NSData *body = request.body;
    4.99 -    size_t size = body.length;
   4.100 -    Assert(size<32768);
   4.101 -    const UInt8 *bytes = body.bytes;
   4.102 -    for( size_t i=0; i<size; i++ )
   4.103 -        AssertEq(bytes[i],i % 256);
   4.104      
   4.105 -    AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
   4.106 -    Assert([request valueOfProperty: @"User-Agent"] != nil);
   4.107 -    AssertEq((size_t)[[request valueOfProperty: @"Size"] intValue], size);
   4.108 +    if ([request.profile isEqualToString: @"BLIPTest/EchoData"]) {
   4.109 +        NSData *body = request.body;
   4.110 +        size_t size = body.length;
   4.111 +        Assert(size<32768);
   4.112 +        const UInt8 *bytes = body.bytes;
   4.113 +        for( size_t i=0; i<size; i++ )
   4.114 +            AssertEq(bytes[i],i % 256);
   4.115 +        
   4.116 +        AssertEqual([request valueOfProperty: @"Content-Type"], @"application/octet-stream");
   4.117 +        Assert([request valueOfProperty: @"User-Agent"] != nil);
   4.118 +        AssertEq((size_t)[[request valueOfProperty: @"Size"] intValue], size);
   4.119  
   4.120 -    [request respondWithData: body contentType: request.contentType];
   4.121 +        [request respondWithData: body contentType: request.contentType];
   4.122 +    } else if ([request.profile isEqualToString: @"BLIPTest/DontHandleMe"]) {
   4.123 +        // Deliberately don't handle this, to test unhandled request handling.
   4.124 +        return NO;
   4.125 +    } else {
   4.126 +        Assert(NO, @"Unknown profile in request %@", request);
   4.127 +    }
   4.128      
   4.129      if( ++ _nReceived == kListenerCloseAfter ) {
   4.130          Log(@"********** Closing BLIPTestListener after %i requests",_nReceived);
   4.131          [connection close];
   4.132      }
   4.133 +    return YES;
   4.134  }
   4.135  
   4.136  - (BOOL) connectionReceivedCloseRequest: (BLIPConnection*)connection;
     5.1 --- a/BLIP/Demo/BLIPEchoServer.m	Tue Jul 21 15:06:15 2009 -0700
     5.2 +++ b/BLIP/Demo/BLIPEchoServer.m	Fri Jul 24 14:06:28 2009 -0700
     5.3 @@ -50,10 +50,11 @@
     5.4      NSLog(@"** %@ failedToOpen: %@",connection,error);
     5.5  }
     5.6  
     5.7 -- (void) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
     5.8 +- (BOOL) connection: (BLIPConnection*)connection receivedRequest: (BLIPRequest*)request
     5.9  {
    5.10      NSLog(@"***** %@ received %@",connection,request);
    5.11      [request respondWithData: request.body contentType: request.contentType];
    5.12 +    return YES;
    5.13  }
    5.14  
    5.15