├── CocoaHTTPServer ├── .hgignore ├── CocoaHTTPServer.h ├── Core │ ├── Categories │ │ ├── DDData.h │ │ ├── DDData.m │ │ ├── DDNumber.h │ │ ├── DDNumber.m │ │ ├── DDRange.h │ │ └── DDRange.m │ ├── HTTPAuthenticationRequest.h │ ├── HTTPAuthenticationRequest.m │ ├── HTTPConnection.h │ ├── HTTPConnection.m │ ├── HTTPLogging.h │ ├── HTTPMessage.h │ ├── HTTPMessage.m │ ├── HTTPResponse.h │ ├── HTTPServer.h │ ├── HTTPServer.m │ ├── Mime │ │ ├── MultipartFormDataParser.h │ │ ├── MultipartFormDataParser.m │ │ ├── MultipartMessageHeader.h │ │ ├── MultipartMessageHeader.m │ │ ├── MultipartMessageHeaderField.h │ │ └── MultipartMessageHeaderField.m │ ├── Responses │ │ ├── HTTPAsyncFileResponse.h │ │ ├── HTTPAsyncFileResponse.m │ │ ├── HTTPDataResponse.h │ │ ├── HTTPDataResponse.m │ │ ├── HTTPDynamicFileResponse.h │ │ ├── HTTPDynamicFileResponse.m │ │ ├── HTTPFileResponse.h │ │ ├── HTTPFileResponse.m │ │ ├── HTTPRedirectResponse.h │ │ └── HTTPRedirectResponse.m │ ├── WebSocket.h │ └── WebSocket.m ├── Extensions │ └── WebDAV │ │ ├── DAVConnection.h │ │ ├── DAVConnection.m │ │ ├── DAVResponse.h │ │ ├── DAVResponse.m │ │ ├── DELETEResponse.h │ │ ├── DELETEResponse.m │ │ ├── PUTResponse.h │ │ └── PUTResponse.m ├── LICENSE.txt ├── README.markdown └── Vendor │ ├── CocoaAsyncSocket │ ├── About.txt │ ├── GCDAsyncSocket.h │ └── GCDAsyncSocket.m │ └── CocoaLumberjack │ ├── About.txt │ ├── DDASLLogger.h │ ├── DDASLLogger.m │ ├── DDAbstractDatabaseLogger.h │ ├── DDAbstractDatabaseLogger.m │ ├── DDFileLogger.h │ ├── DDFileLogger.m │ ├── DDLog.h │ ├── DDLog.m │ ├── DDTTYLogger.h │ ├── DDTTYLogger.m │ └── Extensions │ ├── ContextFilterLogFormatter.h │ ├── ContextFilterLogFormatter.m │ ├── DispatchQueueLogFormatter.h │ ├── DispatchQueueLogFormatter.m │ └── README.txt ├── HTTPServer.xcodeproj └── project.pbxproj ├── HTTPServer ├── HTTPServer-Info.plist ├── HTTPServer-Prefix.pch └── en.lproj │ └── InfoPlist.strings ├── OpenSourceLicenses ├── CocoaHTTPServer.txt ├── ProtocolBuffers.txt └── RoutingHTTPServer.txt ├── OpenSourceVersions └── HTTPServer.plist ├── ProtocolBuffers ├── AbstractMessage.h ├── AbstractMessage.m ├── AbstractMessage_Builder.h ├── AbstractMessage_Builder.m ├── Bootstrap.h ├── CodedInputStream.h ├── CodedInputStream.m ├── CodedOutputStream.h ├── CodedOutputStream.m ├── ConcreteExtensionField.h ├── ConcreteExtensionField.m ├── Descriptor.pb.h ├── Descriptor.pb.m ├── ExtendableMessage.h ├── ExtendableMessage.m ├── ExtendableMessage_Builder.h ├── ExtendableMessage_Builder.m ├── ExtensionField.h ├── ExtensionRegistry.h ├── ExtensionRegistry.m ├── Field.h ├── Field.m ├── ForwardDeclarations.h ├── GeneratedMessage.h ├── GeneratedMessage.m ├── GeneratedMessage_Builder.h ├── GeneratedMessage_Builder.m ├── Message.h ├── Message_Builder.h ├── MutableExtensionRegistry.h ├── MutableExtensionRegistry.m ├── MutableField.h ├── MutableField.m ├── PBArray.h ├── PBArray.m ├── ProtocolBuffers-Info.plist ├── ProtocolBuffers-Prefix.pch ├── ProtocolBuffers.h ├── RingBuffer.h ├── RingBuffer.m ├── TextFormat.h ├── TextFormat.m ├── UnknownFieldSet.h ├── UnknownFieldSet.m ├── UnknownFieldSet_Builder.h ├── UnknownFieldSet_Builder.m ├── Utilities.h ├── Utilities.m ├── WireFormat.h ├── WireFormat.m └── en.lproj │ └── InfoPlist.strings └── Routing HTTP Server ├── HTTPResponseProxy.h ├── HTTPResponseProxy.m ├── LICENSE.txt ├── Route.h ├── Route.m ├── RouteRequest.h ├── RouteRequest.m ├── RouteResponse.h ├── RouteResponse.m ├── RoutingConnection.h ├── RoutingConnection.m ├── RoutingHTTPServer.h └── RoutingHTTPServer.m /CocoaHTTPServer/.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | 3 | Samples/*/build 4 | *.pbxuser 5 | *.mode1v3 6 | *.xcuserdatad 7 | -------------------------------------------------------------------------------- /CocoaHTTPServer/CocoaHTTPServer.h: -------------------------------------------------------------------------------- 1 | // 2 | // CocoaHTTPServer.h 3 | // HTTPServer 4 | // 5 | // Created by Jason Dreisbach on 8/29/12. 6 | // 7 | // 8 | 9 | #import "HTTPServer.h" 10 | #import "HTTPMessage.h" 11 | #import "HTTPConnection.h" 12 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDData.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface NSData (DDData) 4 | 5 | - (NSData *)md5Digest; 6 | 7 | - (NSData *)sha1Digest; 8 | 9 | - (NSString *)hexStringValue; 10 | 11 | - (NSString *)base64Encoded; 12 | - (NSData *)base64Decoded; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDData.m: -------------------------------------------------------------------------------- 1 | #import "DDData.h" 2 | #import 3 | 4 | 5 | @implementation NSData (DDData) 6 | 7 | static char encodingTable[64] = { 8 | 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 9 | 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 10 | 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 11 | 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' }; 12 | 13 | - (NSData *)md5Digest 14 | { 15 | unsigned char result[CC_MD5_DIGEST_LENGTH]; 16 | 17 | CC_MD5([self bytes], (CC_LONG)[self length], result); 18 | return [NSData dataWithBytes:result length:CC_MD5_DIGEST_LENGTH]; 19 | } 20 | 21 | - (NSData *)sha1Digest 22 | { 23 | unsigned char result[CC_SHA1_DIGEST_LENGTH]; 24 | 25 | CC_SHA1([self bytes], (CC_LONG)[self length], result); 26 | return [NSData dataWithBytes:result length:CC_SHA1_DIGEST_LENGTH]; 27 | } 28 | 29 | - (NSString *)hexStringValue 30 | { 31 | NSMutableString *stringBuffer = [NSMutableString stringWithCapacity:([self length] * 2)]; 32 | 33 | const unsigned char *dataBuffer = [self bytes]; 34 | int i; 35 | 36 | for (i = 0; i < [self length]; ++i) 37 | { 38 | [stringBuffer appendFormat:@"%02x", (unsigned int)dataBuffer[i]]; 39 | } 40 | 41 | return [stringBuffer copy]; 42 | } 43 | 44 | - (NSString *)base64Encoded 45 | { 46 | const unsigned char *bytes = [self bytes]; 47 | NSMutableString *result = [NSMutableString stringWithCapacity:[self length]]; 48 | unsigned long ixtext = 0; 49 | unsigned long lentext = [self length]; 50 | long ctremaining = 0; 51 | unsigned char inbuf[3], outbuf[4]; 52 | unsigned short i = 0; 53 | unsigned short charsonline = 0, ctcopy = 0; 54 | unsigned long ix = 0; 55 | 56 | while( YES ) 57 | { 58 | ctremaining = lentext - ixtext; 59 | if( ctremaining <= 0 ) break; 60 | 61 | for( i = 0; i < 3; i++ ) { 62 | ix = ixtext + i; 63 | if( ix < lentext ) inbuf[i] = bytes[ix]; 64 | else inbuf [i] = 0; 65 | } 66 | 67 | outbuf [0] = (inbuf [0] & 0xFC) >> 2; 68 | outbuf [1] = ((inbuf [0] & 0x03) << 4) | ((inbuf [1] & 0xF0) >> 4); 69 | outbuf [2] = ((inbuf [1] & 0x0F) << 2) | ((inbuf [2] & 0xC0) >> 6); 70 | outbuf [3] = inbuf [2] & 0x3F; 71 | ctcopy = 4; 72 | 73 | switch( ctremaining ) 74 | { 75 | case 1: 76 | ctcopy = 2; 77 | break; 78 | case 2: 79 | ctcopy = 3; 80 | break; 81 | } 82 | 83 | for( i = 0; i < ctcopy; i++ ) 84 | [result appendFormat:@"%c", encodingTable[outbuf[i]]]; 85 | 86 | for( i = ctcopy; i < 4; i++ ) 87 | [result appendString:@"="]; 88 | 89 | ixtext += 3; 90 | charsonline += 4; 91 | } 92 | 93 | return [NSString stringWithString:result]; 94 | } 95 | 96 | - (NSData *)base64Decoded 97 | { 98 | const unsigned char *bytes = [self bytes]; 99 | NSMutableData *result = [NSMutableData dataWithCapacity:[self length]]; 100 | 101 | unsigned long ixtext = 0; 102 | unsigned long lentext = [self length]; 103 | unsigned char ch = 0; 104 | unsigned char inbuf[4] = {0, 0, 0, 0}; 105 | unsigned char outbuf[3] = {0, 0, 0}; 106 | short i = 0, ixinbuf = 0; 107 | BOOL flignore = NO; 108 | BOOL flendtext = NO; 109 | 110 | while( YES ) 111 | { 112 | if( ixtext >= lentext ) break; 113 | ch = bytes[ixtext++]; 114 | flignore = NO; 115 | 116 | if( ( ch >= 'A' ) && ( ch <= 'Z' ) ) ch = ch - 'A'; 117 | else if( ( ch >= 'a' ) && ( ch <= 'z' ) ) ch = ch - 'a' + 26; 118 | else if( ( ch >= '0' ) && ( ch <= '9' ) ) ch = ch - '0' + 52; 119 | else if( ch == '+' ) ch = 62; 120 | else if( ch == '=' ) flendtext = YES; 121 | else if( ch == '/' ) ch = 63; 122 | else flignore = YES; 123 | 124 | if( ! flignore ) 125 | { 126 | short ctcharsinbuf = 3; 127 | BOOL flbreak = NO; 128 | 129 | if( flendtext ) 130 | { 131 | if( ! ixinbuf ) break; 132 | if( ( ixinbuf == 1 ) || ( ixinbuf == 2 ) ) ctcharsinbuf = 1; 133 | else ctcharsinbuf = 2; 134 | ixinbuf = 3; 135 | flbreak = YES; 136 | } 137 | 138 | inbuf [ixinbuf++] = ch; 139 | 140 | if( ixinbuf == 4 ) 141 | { 142 | ixinbuf = 0; 143 | outbuf [0] = ( inbuf[0] << 2 ) | ( ( inbuf[1] & 0x30) >> 4 ); 144 | outbuf [1] = ( ( inbuf[1] & 0x0F ) << 4 ) | ( ( inbuf[2] & 0x3C ) >> 2 ); 145 | outbuf [2] = ( ( inbuf[2] & 0x03 ) << 6 ) | ( inbuf[3] & 0x3F ); 146 | 147 | for( i = 0; i < ctcharsinbuf; i++ ) 148 | [result appendBytes:&outbuf[i] length:1]; 149 | } 150 | 151 | if( flbreak ) break; 152 | } 153 | } 154 | 155 | return [NSData dataWithData:result]; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDNumber.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | @interface NSNumber (DDNumber) 5 | 6 | + (BOOL)parseString:(NSString *)str intoSInt64:(SInt64 *)pNum; 7 | + (BOOL)parseString:(NSString *)str intoUInt64:(UInt64 *)pNum; 8 | 9 | + (BOOL)parseString:(NSString *)str intoNSInteger:(NSInteger *)pNum; 10 | + (BOOL)parseString:(NSString *)str intoNSUInteger:(NSUInteger *)pNum; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDNumber.m: -------------------------------------------------------------------------------- 1 | #import "DDNumber.h" 2 | 3 | 4 | @implementation NSNumber (DDNumber) 5 | 6 | + (BOOL)parseString:(NSString *)str intoSInt64:(SInt64 *)pNum 7 | { 8 | if(str == nil) 9 | { 10 | *pNum = 0; 11 | return NO; 12 | } 13 | 14 | errno = 0; 15 | 16 | // On both 32-bit and 64-bit machines, long long = 64 bit 17 | 18 | *pNum = strtoll([str UTF8String], NULL, 10); 19 | 20 | // under Instruments, strtoll can succeed with errno==ETIMEDOUT 21 | if(errno == ERANGE || errno == EINVAL) 22 | return NO; 23 | else 24 | return YES; 25 | } 26 | 27 | + (BOOL)parseString:(NSString *)str intoUInt64:(UInt64 *)pNum 28 | { 29 | if(str == nil) 30 | { 31 | *pNum = 0; 32 | return NO; 33 | } 34 | 35 | errno = 0; 36 | 37 | // On both 32-bit and 64-bit machines, unsigned long long = 64 bit 38 | 39 | *pNum = strtoull([str UTF8String], NULL, 10); 40 | 41 | // under Instruments, strtoull can succeed with errno==ETIMEDOUT 42 | if(errno == ERANGE || errno == EINVAL) 43 | return NO; 44 | else 45 | return YES; 46 | } 47 | 48 | + (BOOL)parseString:(NSString *)str intoNSInteger:(NSInteger *)pNum 49 | { 50 | if(str == nil) 51 | { 52 | *pNum = 0; 53 | return NO; 54 | } 55 | 56 | errno = 0; 57 | 58 | // On LP64, NSInteger = long = 64 bit 59 | // Otherwise, NSInteger = int = long = 32 bit 60 | 61 | *pNum = strtol([str UTF8String], NULL, 10); 62 | 63 | // under Instruments, strtol can succeed with errno==ETIMEDOUT 64 | if(errno == ERANGE || errno == EINVAL) 65 | return NO; 66 | else 67 | return YES; 68 | } 69 | 70 | + (BOOL)parseString:(NSString *)str intoNSUInteger:(NSUInteger *)pNum 71 | { 72 | if(str == nil) 73 | { 74 | *pNum = 0; 75 | return NO; 76 | } 77 | 78 | errno = 0; 79 | 80 | // On LP64, NSUInteger = unsigned long = 64 bit 81 | // Otherwise, NSUInteger = unsigned int = unsigned long = 32 bit 82 | 83 | *pNum = strtoul([str UTF8String], NULL, 10); 84 | 85 | // under Instruments, strtoul can succeed with errno==ETIMEDOUT 86 | if(errno == ERANGE || errno == EINVAL) 87 | return NO; 88 | else 89 | return YES; 90 | } 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDRange.h: -------------------------------------------------------------------------------- 1 | /** 2 | * DDRange is the functional equivalent of a 64 bit NSRange. 3 | * The HTTP Server is designed to support very large files. 4 | * On 32 bit architectures (ppc, i386) NSRange uses unsigned 32 bit integers. 5 | * This only supports a range of up to 4 gigabytes. 6 | * By defining our own variant, we can support a range up to 16 exabytes. 7 | * 8 | * All effort is given such that DDRange functions EXACTLY the same as NSRange. 9 | **/ 10 | 11 | #import 12 | #import 13 | 14 | @class NSString; 15 | 16 | typedef struct _DDRange { 17 | UInt64 location; 18 | UInt64 length; 19 | } DDRange; 20 | 21 | typedef DDRange *DDRangePointer; 22 | 23 | NS_INLINE DDRange DDMakeRange(UInt64 loc, UInt64 len) { 24 | DDRange r; 25 | r.location = loc; 26 | r.length = len; 27 | return r; 28 | } 29 | 30 | NS_INLINE UInt64 DDMaxRange(DDRange range) { 31 | return (range.location + range.length); 32 | } 33 | 34 | NS_INLINE BOOL DDLocationInRange(UInt64 loc, DDRange range) { 35 | return (loc - range.location < range.length); 36 | } 37 | 38 | NS_INLINE BOOL DDEqualRanges(DDRange range1, DDRange range2) { 39 | return ((range1.location == range2.location) && (range1.length == range2.length)); 40 | } 41 | 42 | FOUNDATION_EXPORT DDRange DDUnionRange(DDRange range1, DDRange range2); 43 | FOUNDATION_EXPORT DDRange DDIntersectionRange(DDRange range1, DDRange range2); 44 | FOUNDATION_EXPORT NSString *DDStringFromRange(DDRange range); 45 | FOUNDATION_EXPORT DDRange DDRangeFromString(NSString *aString); 46 | 47 | NSInteger DDRangeCompare(DDRangePointer pDDRange1, DDRangePointer pDDRange2); 48 | 49 | @interface NSValue (NSValueDDRangeExtensions) 50 | 51 | + (NSValue *)valueWithDDRange:(DDRange)range; 52 | - (DDRange)ddrangeValue; 53 | 54 | - (NSInteger)ddrangeCompare:(NSValue *)ddrangeValue; 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Categories/DDRange.m: -------------------------------------------------------------------------------- 1 | #import "DDRange.h" 2 | #import "DDNumber.h" 3 | 4 | DDRange DDUnionRange(DDRange range1, DDRange range2) 5 | { 6 | DDRange result; 7 | 8 | result.location = MIN(range1.location, range2.location); 9 | result.length = MAX(DDMaxRange(range1), DDMaxRange(range2)) - result.location; 10 | 11 | return result; 12 | } 13 | 14 | DDRange DDIntersectionRange(DDRange range1, DDRange range2) 15 | { 16 | DDRange result; 17 | 18 | if((DDMaxRange(range1) < range2.location) || (DDMaxRange(range2) < range1.location)) 19 | { 20 | return DDMakeRange(0, 0); 21 | } 22 | 23 | result.location = MAX(range1.location, range2.location); 24 | result.length = MIN(DDMaxRange(range1), DDMaxRange(range2)) - result.location; 25 | 26 | return result; 27 | } 28 | 29 | NSString *DDStringFromRange(DDRange range) 30 | { 31 | return [NSString stringWithFormat:@"{%qu, %qu}", range.location, range.length]; 32 | } 33 | 34 | DDRange DDRangeFromString(NSString *aString) 35 | { 36 | DDRange result = DDMakeRange(0, 0); 37 | 38 | // NSRange will ignore '-' characters, but not '+' characters 39 | NSCharacterSet *cset = [NSCharacterSet characterSetWithCharactersInString:@"+0123456789"]; 40 | 41 | NSScanner *scanner = [NSScanner scannerWithString:aString]; 42 | [scanner setCharactersToBeSkipped:[cset invertedSet]]; 43 | 44 | NSString *str1 = nil; 45 | NSString *str2 = nil; 46 | 47 | BOOL found1 = [scanner scanCharactersFromSet:cset intoString:&str1]; 48 | BOOL found2 = [scanner scanCharactersFromSet:cset intoString:&str2]; 49 | 50 | if(found1) [NSNumber parseString:str1 intoUInt64:&result.location]; 51 | if(found2) [NSNumber parseString:str2 intoUInt64:&result.length]; 52 | 53 | return result; 54 | } 55 | 56 | NSInteger DDRangeCompare(DDRangePointer pDDRange1, DDRangePointer pDDRange2) 57 | { 58 | // Comparison basis: 59 | // Which range would you encouter first if you started at zero, and began walking towards infinity. 60 | // If you encouter both ranges at the same time, which range would end first. 61 | 62 | if(pDDRange1->location < pDDRange2->location) 63 | { 64 | return NSOrderedAscending; 65 | } 66 | if(pDDRange1->location > pDDRange2->location) 67 | { 68 | return NSOrderedDescending; 69 | } 70 | if(pDDRange1->length < pDDRange2->length) 71 | { 72 | return NSOrderedAscending; 73 | } 74 | if(pDDRange1->length > pDDRange2->length) 75 | { 76 | return NSOrderedDescending; 77 | } 78 | 79 | return NSOrderedSame; 80 | } 81 | 82 | @implementation NSValue (NSValueDDRangeExtensions) 83 | 84 | + (NSValue *)valueWithDDRange:(DDRange)range 85 | { 86 | return [NSValue valueWithBytes:&range objCType:@encode(DDRange)]; 87 | } 88 | 89 | - (DDRange)ddrangeValue 90 | { 91 | DDRange result; 92 | [self getValue:&result]; 93 | return result; 94 | } 95 | 96 | - (NSInteger)ddrangeCompare:(NSValue *)other 97 | { 98 | DDRange r1 = [self ddrangeValue]; 99 | DDRange r2 = [other ddrangeValue]; 100 | 101 | return DDRangeCompare(&r1, &r2); 102 | } 103 | 104 | @end 105 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/HTTPAuthenticationRequest.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #if TARGET_OS_IPHONE 4 | // Note: You may need to add the CFNetwork Framework to your project 5 | #import 6 | #endif 7 | 8 | @class HTTPMessage; 9 | 10 | 11 | @interface HTTPAuthenticationRequest : NSObject 12 | { 13 | BOOL isBasic; 14 | BOOL isDigest; 15 | 16 | NSString *base64Credentials; 17 | 18 | NSString *username; 19 | NSString *realm; 20 | NSString *nonce; 21 | NSString *uri; 22 | NSString *qop; 23 | NSString *nc; 24 | NSString *cnonce; 25 | NSString *response; 26 | } 27 | - (id)initWithRequest:(HTTPMessage *)request; 28 | 29 | - (BOOL)isBasic; 30 | - (BOOL)isDigest; 31 | 32 | // Basic 33 | - (NSString *)base64Credentials; 34 | 35 | // Digest 36 | - (NSString *)username; 37 | - (NSString *)realm; 38 | - (NSString *)nonce; 39 | - (NSString *)uri; 40 | - (NSString *)qop; 41 | - (NSString *)nc; 42 | - (NSString *)cnonce; 43 | - (NSString *)response; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/HTTPConnection.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class GCDAsyncSocket; 4 | @class HTTPMessage; 5 | @class HTTPServer; 6 | @class WebSocket; 7 | @protocol HTTPResponse; 8 | 9 | 10 | #define HTTPConnectionDidDieNotification @"HTTPConnectionDidDie" 11 | 12 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 13 | #pragma mark - 14 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 15 | 16 | @interface HTTPConfig : NSObject 17 | { 18 | HTTPServer __unsafe_unretained *server; 19 | NSString __strong *documentRoot; 20 | dispatch_queue_t queue; 21 | } 22 | 23 | - (id)initWithServer:(HTTPServer *)server documentRoot:(NSString *)documentRoot; 24 | - (id)initWithServer:(HTTPServer *)server documentRoot:(NSString *)documentRoot queue:(dispatch_queue_t)q; 25 | 26 | @property (nonatomic, unsafe_unretained, readonly) HTTPServer *server; 27 | @property (nonatomic, strong, readonly) NSString *documentRoot; 28 | @property (nonatomic, readonly) dispatch_queue_t queue; 29 | 30 | @end 31 | 32 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 33 | #pragma mark - 34 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 35 | 36 | @interface HTTPConnection : NSObject 37 | { 38 | dispatch_queue_t connectionQueue; 39 | GCDAsyncSocket *asyncSocket; 40 | HTTPConfig *config; 41 | 42 | BOOL started; 43 | 44 | HTTPMessage *request; 45 | unsigned int numHeaderLines; 46 | 47 | BOOL sentResponseHeaders; 48 | 49 | NSString *nonce; 50 | long lastNC; 51 | 52 | NSObject *httpResponse; 53 | 54 | NSMutableArray *ranges; 55 | NSMutableArray *ranges_headers; 56 | NSString *ranges_boundry; 57 | int rangeIndex; 58 | 59 | UInt64 requestContentLength; 60 | UInt64 requestContentLengthReceived; 61 | UInt64 requestChunkSize; 62 | UInt64 requestChunkSizeReceived; 63 | 64 | NSMutableArray *responseDataSizes; 65 | UInt64 posthumousCountedBytesWritten; 66 | } 67 | 68 | - (id)initWithAsyncSocket:(GCDAsyncSocket *)newSocket configuration:(HTTPConfig *)aConfig; 69 | 70 | - (void)start; 71 | - (void)stop; 72 | 73 | - (void)startConnection; 74 | 75 | - (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path; 76 | - (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path; 77 | 78 | - (BOOL)isSecureServer; 79 | - (NSArray *)sslIdentityAndCertificates; 80 | 81 | - (BOOL)isPasswordProtected:(NSString *)path; 82 | - (BOOL)useDigestAccessAuthentication; 83 | - (NSString *)realm; 84 | - (NSString *)passwordForUser:(NSString *)username; 85 | 86 | - (NSDictionary *)parseParams:(NSString *)query; 87 | - (NSDictionary *)parseGetParams; 88 | 89 | - (NSString *)requestURI; 90 | 91 | - (NSArray *)directoryIndexFileNames; 92 | - (NSString *)filePathForURI:(NSString *)path; 93 | - (NSString *)filePathForURI:(NSString *)path allowDirectory:(BOOL)allowDirectory; 94 | - (NSObject *)httpResponseForMethod:(NSString *)method URI:(NSString *)path; 95 | - (WebSocket *)webSocketForURI:(NSString *)path; 96 | - (NSString *)connectedHost; 97 | - (uint16_t)connectedPort; 98 | 99 | - (void)prepareForBodyWithSize:(UInt64)contentLength; 100 | - (void)processBodyData:(NSData *)postDataChunk; 101 | - (void)finishBody; 102 | 103 | - (void)handleVersionNotSupported:(NSString *)version; 104 | - (void)handleAuthenticationFailed; 105 | - (void)handleResourceNotFound; 106 | - (void)handleInvalidRequest:(NSData *)data; 107 | - (void)handleUnknownMethod:(NSString *)method; 108 | - (void)handleNotImplemented; 109 | - (void)handleNotAvailable; 110 | 111 | - (NSData *)preprocessResponse:(HTTPMessage *)response; 112 | - (NSData *)preprocessErrorResponse:(HTTPMessage *)response; 113 | 114 | - (void)finishResponse; 115 | 116 | - (BOOL)shouldDie; 117 | - (void)die; 118 | 119 | - (UInt64)bodyBytesWritten; 120 | 121 | @end 122 | 123 | @interface HTTPConnection (AsynchronousHTTPResponse) 124 | - (void)responseHasAvailableData:(NSObject *)sender; 125 | - (void)responseDidAbort:(NSObject *)sender; 126 | @end 127 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/HTTPMessage.h: -------------------------------------------------------------------------------- 1 | /** 2 | * The HTTPMessage class is a simple Objective-C wrapper around Apple's CFHTTPMessage class. 3 | **/ 4 | 5 | #import 6 | 7 | #if TARGET_OS_IPHONE 8 | // Note: You may need to add the CFNetwork Framework to your project 9 | #import 10 | #endif 11 | 12 | #define HTTPVersion1_0 ((NSString *)kCFHTTPVersion1_0) 13 | #define HTTPVersion1_1 ((NSString *)kCFHTTPVersion1_1) 14 | 15 | 16 | @interface HTTPMessage : NSObject 17 | { 18 | CFHTTPMessageRef message; 19 | } 20 | @property (readonly)CFHTTPMessageRef message; 21 | 22 | - (id)initEmptyRequest; 23 | 24 | - (id)initRequestWithMethod:(NSString *)method URL:(NSURL *)url version:(NSString *)version; 25 | 26 | - (id)initResponseWithStatusCode:(NSInteger)code description:(NSString *)description version:(NSString *)version; 27 | 28 | - (BOOL)appendData:(NSData *)data; 29 | 30 | - (BOOL)isHeaderComplete; 31 | 32 | - (NSString *)version; 33 | 34 | - (NSString *)method; 35 | - (NSURL *)url; 36 | 37 | - (NSInteger)statusCode; 38 | 39 | - (NSDictionary *)allHeaderFields; 40 | - (NSString *)headerField:(NSString *)headerField; 41 | 42 | - (void)setHeaderField:(NSString *)headerField value:(NSString *)headerFieldValue; 43 | 44 | - (NSData *)messageData; 45 | 46 | - (NSData *)body; 47 | - (void)setBody:(NSData *)body; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/HTTPMessage.m: -------------------------------------------------------------------------------- 1 | #import "HTTPMessage.h" 2 | 3 | #if ! __has_feature(objc_arc) 4 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 5 | #endif 6 | 7 | 8 | @implementation HTTPMessage 9 | @synthesize message; 10 | 11 | - (id)initEmptyRequest 12 | { 13 | if ((self = [super init])) 14 | { 15 | message = CFHTTPMessageCreateEmpty(NULL, YES); 16 | } 17 | return self; 18 | } 19 | 20 | - (id)initRequestWithMethod:(NSString *)method URL:(NSURL *)url version:(NSString *)version 21 | { 22 | if ((self = [super init])) 23 | { 24 | message = CFHTTPMessageCreateRequest(NULL, 25 | (__bridge CFStringRef)method, 26 | (__bridge CFURLRef)url, 27 | (__bridge CFStringRef)version); 28 | } 29 | return self; 30 | } 31 | 32 | - (id)initResponseWithStatusCode:(NSInteger)code description:(NSString *)description version:(NSString *)version 33 | { 34 | if ((self = [super init])) 35 | { 36 | message = CFHTTPMessageCreateResponse(NULL, 37 | (CFIndex)code, 38 | (__bridge CFStringRef)description, 39 | (__bridge CFStringRef)version); 40 | } 41 | return self; 42 | } 43 | 44 | - (void)dealloc 45 | { 46 | if (message) 47 | { 48 | CFRelease(message); 49 | } 50 | } 51 | 52 | - (BOOL)appendData:(NSData *)data 53 | { 54 | return CFHTTPMessageAppendBytes(message, [data bytes], [data length]); 55 | } 56 | 57 | - (BOOL)isHeaderComplete 58 | { 59 | return CFHTTPMessageIsHeaderComplete(message); 60 | } 61 | 62 | - (NSString *)version 63 | { 64 | return (__bridge_transfer NSString *)CFHTTPMessageCopyVersion(message); 65 | } 66 | 67 | - (NSString *)method 68 | { 69 | return (__bridge_transfer NSString *)CFHTTPMessageCopyRequestMethod(message); 70 | } 71 | 72 | - (NSURL *)url 73 | { 74 | return (__bridge_transfer NSURL *)CFHTTPMessageCopyRequestURL(message); 75 | } 76 | 77 | - (NSInteger)statusCode 78 | { 79 | return (NSInteger)CFHTTPMessageGetResponseStatusCode(message); 80 | } 81 | 82 | - (NSDictionary *)allHeaderFields 83 | { 84 | return (__bridge_transfer NSDictionary *)CFHTTPMessageCopyAllHeaderFields(message); 85 | } 86 | 87 | - (NSString *)headerField:(NSString *)headerField 88 | { 89 | return (__bridge_transfer NSString *)CFHTTPMessageCopyHeaderFieldValue(message, (__bridge CFStringRef)headerField); 90 | } 91 | 92 | - (void)setHeaderField:(NSString *)headerField value:(NSString *)headerFieldValue 93 | { 94 | CFHTTPMessageSetHeaderFieldValue(message, 95 | (__bridge CFStringRef)headerField, 96 | (__bridge CFStringRef)headerFieldValue); 97 | } 98 | 99 | - (NSData *)messageData 100 | { 101 | return (__bridge_transfer NSData *)CFHTTPMessageCopySerializedMessage(message); 102 | } 103 | 104 | - (NSData *)body 105 | { 106 | return (__bridge_transfer NSData *)CFHTTPMessageCopyBody(message); 107 | } 108 | 109 | - (void)setBody:(NSData *)body 110 | { 111 | CFHTTPMessageSetBody(message, (__bridge CFDataRef)body); 112 | } 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Mime/MultipartFormDataParser.h: -------------------------------------------------------------------------------- 1 | 2 | #import "MultipartMessageHeader.h" 3 | 4 | /* 5 | Part one: http://tools.ietf.org/html/rfc2045 (Format of Internet Message Bodies) 6 | Part two: http://tools.ietf.org/html/rfc2046 (Media Types) 7 | Part three: http://tools.ietf.org/html/rfc2047 (Message Header Extensions for Non-ASCII Text) 8 | Part four: http://tools.ietf.org/html/rfc4289 (Registration Procedures) 9 | Part five: http://tools.ietf.org/html/rfc2049 (Conformance Criteria and Examples) 10 | 11 | Internet message format: http://tools.ietf.org/html/rfc2822 12 | 13 | Multipart/form-data http://tools.ietf.org/html/rfc2388 14 | */ 15 | 16 | @class MultipartFormDataParser; 17 | 18 | //----------------------------------------------------------------- 19 | // protocol MultipartFormDataParser 20 | //----------------------------------------------------------------- 21 | 22 | @protocol MultipartFormDataParserDelegate 23 | @optional 24 | - (void) processContent:(NSData*) data WithHeader:(MultipartMessageHeader*) header; 25 | - (void) processEndOfPartWithHeader:(MultipartMessageHeader*) header; 26 | - (void) processPreambleData:(NSData*) data; 27 | - (void) processEpilogueData:(NSData*) data; 28 | - (void) processStartOfPartWithHeader:(MultipartMessageHeader*) header; 29 | @end 30 | 31 | //----------------------------------------------------------------- 32 | // interface MultipartFormDataParser 33 | //----------------------------------------------------------------- 34 | 35 | @interface MultipartFormDataParser : NSObject { 36 | NSMutableData* pendingData; 37 | NSData* boundaryData; 38 | MultipartMessageHeader* currentHeader; 39 | 40 | BOOL waitingForCRLF; 41 | BOOL reachedEpilogue; 42 | BOOL processedPreamble; 43 | BOOL checkForContentEnd; 44 | 45 | #if __has_feature(objc_arc_weak) 46 | __weak id delegate; 47 | #else 48 | __unsafe_unretained id delegate; 49 | #endif 50 | int currentEncoding; 51 | NSStringEncoding formEncoding; 52 | } 53 | 54 | - (BOOL) appendData:(NSData*) data; 55 | 56 | - (id) initWithBoundary:(NSString*) boundary formEncoding:(NSStringEncoding) formEncoding; 57 | 58 | #if __has_feature(objc_arc_weak) 59 | @property(weak, readwrite) id delegate; 60 | #else 61 | @property(unsafe_unretained, readwrite) id delegate; 62 | #endif 63 | @property(readwrite) NSStringEncoding formEncoding; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Mime/MultipartMessageHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // MultipartMessagePart.h 3 | // HttpServer 4 | // 5 | // Created by Валерий Гаврилов on 29.03.12. 6 | // Copyright (c) 2012 LLC "Online Publishing Partners" (onlinepp.ru). All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | //----------------------------------------------------------------- 13 | // interface MultipartMessageHeader 14 | //----------------------------------------------------------------- 15 | enum { 16 | contentTransferEncoding_unknown, 17 | contentTransferEncoding_7bit, 18 | contentTransferEncoding_8bit, 19 | contentTransferEncoding_binary, 20 | contentTransferEncoding_base64, 21 | contentTransferEncoding_quotedPrintable, 22 | }; 23 | 24 | @interface MultipartMessageHeader : NSObject { 25 | NSMutableDictionary* fields; 26 | int encoding; 27 | NSString* contentDispositionName; 28 | } 29 | @property (strong,readonly) NSDictionary* fields; 30 | @property (readonly) int encoding; 31 | 32 | - (id) initWithData:(NSData*) data formEncoding:(NSStringEncoding) encoding; 33 | @end 34 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Mime/MultipartMessageHeader.m: -------------------------------------------------------------------------------- 1 | // 2 | // MultipartMessagePart.m 3 | // HttpServer 4 | // 5 | // Created by Валерий Гаврилов on 29.03.12. 6 | // Copyright (c) 2012 LLC "Online Publishing Partners" (onlinepp.ru). All rights reserved. 7 | 8 | #import "MultipartMessageHeader.h" 9 | #import "MultipartMessageHeaderField.h" 10 | 11 | #import "HTTPLogging.h" 12 | 13 | //----------------------------------------------------------------- 14 | #pragma mark log level 15 | 16 | #ifdef DEBUG 17 | static const int httpLogLevel = HTTP_LOG_LEVEL_WARN; 18 | #else 19 | static const int httpLogLevel = HTTP_LOG_LEVEL_WARN; 20 | #endif 21 | 22 | //----------------------------------------------------------------- 23 | // implementation MultipartMessageHeader 24 | //----------------------------------------------------------------- 25 | 26 | 27 | @implementation MultipartMessageHeader 28 | @synthesize fields,encoding; 29 | 30 | 31 | - (id) initWithData:(NSData *)data formEncoding:(NSStringEncoding) formEncoding { 32 | if( nil == (self = [super init]) ) { 33 | return self; 34 | } 35 | 36 | fields = [[NSMutableDictionary alloc] initWithCapacity:1]; 37 | 38 | // In case encoding is not mentioned, 39 | encoding = contentTransferEncoding_unknown; 40 | 41 | char* bytes = (char*)data.bytes; 42 | int length = data.length; 43 | int offset = 0; 44 | 45 | // split header into header fields, separated by \r\n 46 | uint16_t fields_separator = 0x0A0D; // \r\n 47 | while( offset < length - 2 ) { 48 | 49 | // the !isspace condition is to support header unfolding 50 | if( (*(uint16_t*) (bytes+offset) == fields_separator) && ((offset == length - 2) || !(isspace(bytes[offset+2])) )) { 51 | NSData* fieldData = [NSData dataWithBytesNoCopy:bytes length:offset freeWhenDone:NO]; 52 | MultipartMessageHeaderField* field = [[MultipartMessageHeaderField alloc] initWithData: fieldData contentEncoding:formEncoding]; 53 | if( field ) { 54 | [fields setObject:field forKey:field.name]; 55 | HTTPLogVerbose(@"MultipartFormDataParser: Processed Header field '%@'",field.name); 56 | } 57 | else { 58 | NSString* fieldStr = [[NSString alloc] initWithData:fieldData encoding:NSASCIIStringEncoding]; 59 | HTTPLogWarn(@"MultipartFormDataParser: Failed to parse MIME header field. Input ASCII string:%@",fieldStr); 60 | } 61 | 62 | // move to the next header field 63 | bytes += offset + 2; 64 | length -= offset + 2; 65 | offset = 0; 66 | continue; 67 | } 68 | ++ offset; 69 | } 70 | 71 | if( !fields.count ) { 72 | // it was an empty header. 73 | // we have to set default values. 74 | // default header. 75 | [fields setObject:@"text/plain" forKey:@"Content-Type"]; 76 | } 77 | 78 | return self; 79 | } 80 | 81 | - (NSString *)description { 82 | return [NSString stringWithFormat:@"%@",fields]; 83 | } 84 | 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Mime/MultipartMessageHeaderField.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | //----------------------------------------------------------------- 5 | // interface MultipartMessageHeaderField 6 | //----------------------------------------------------------------- 7 | 8 | @interface MultipartMessageHeaderField : NSObject { 9 | NSString* name; 10 | NSString* value; 11 | NSMutableDictionary* params; 12 | } 13 | 14 | @property (strong, readonly) NSString* value; 15 | @property (strong, readonly) NSDictionary* params; 16 | @property (strong, readonly) NSString* name; 17 | 18 | //- (id) initWithLine:(NSString*) line; 19 | //- (id) initWithName:(NSString*) paramName value:(NSString*) paramValue; 20 | 21 | - (id) initWithData:(NSData*) data contentEncoding:(NSStringEncoding) encoding; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPAsyncFileResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | 4 | @class HTTPConnection; 5 | 6 | /** 7 | * This is an asynchronous version of HTTPFileResponse. 8 | * It reads data from the given file asynchronously via GCD. 9 | * 10 | * It may be overriden to allow custom post-processing of the data that has been read from the file. 11 | * An example of this is the HTTPDynamicFileResponse class. 12 | **/ 13 | 14 | @interface HTTPAsyncFileResponse : NSObject 15 | { 16 | HTTPConnection *connection; 17 | 18 | NSString *filePath; 19 | UInt64 fileLength; 20 | UInt64 fileOffset; // File offset as pertains to data given to connection 21 | UInt64 readOffset; // File offset as pertains to data read from file (but maybe not returned to connection) 22 | 23 | BOOL aborted; 24 | 25 | NSData *data; 26 | 27 | int fileFD; 28 | void *readBuffer; 29 | NSUInteger readBufferSize; // Malloced size of readBuffer 30 | NSUInteger readBufferOffset; // Offset within readBuffer where the end of existing data is 31 | NSUInteger readRequestLength; 32 | dispatch_queue_t readQueue; 33 | dispatch_source_t readSource; 34 | BOOL readSourceSuspended; 35 | } 36 | 37 | - (id)initWithFilePath:(NSString *)filePath forConnection:(HTTPConnection *)connection; 38 | - (NSString *)filePath; 39 | 40 | @end 41 | 42 | /** 43 | * Explanation of Variables (excluding those that are obvious) 44 | * 45 | * fileOffset 46 | * This is the number of bytes that have been returned to the connection via the readDataOfLength method. 47 | * If 1KB of data has been read from the file, but none of that data has yet been returned to the connection, 48 | * then the fileOffset variable remains at zero. 49 | * This variable is used in the calculation of the isDone method. 50 | * Only after all data has been returned to the connection are we actually done. 51 | * 52 | * readOffset 53 | * Represents the offset of the file descriptor. 54 | * In other words, the file position indidcator for our read stream. 55 | * It might be easy to think of it as the total number of bytes that have been read from the file. 56 | * However, this isn't entirely accurate, as the setOffset: method may have caused us to 57 | * jump ahead in the file (lseek). 58 | * 59 | * readBuffer 60 | * Malloc'd buffer to hold data read from the file. 61 | * 62 | * readBufferSize 63 | * Total allocation size of malloc'd buffer. 64 | * 65 | * readBufferOffset 66 | * Represents the position in the readBuffer where we should store new bytes. 67 | * 68 | * readRequestLength 69 | * The total number of bytes that were requested from the connection. 70 | * It's OK if we return a lesser number of bytes to the connection. 71 | * It's NOT OK if we return a greater number of bytes to the connection. 72 | * Doing so would disrupt proper support for range requests. 73 | * If, however, the response is chunked then we don't need to worry about this. 74 | * Chunked responses inheritly don't support range requests. 75 | **/ -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPDataResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | 4 | 5 | @interface HTTPDataResponse : NSObject 6 | { 7 | NSUInteger offset; 8 | NSData *data; 9 | } 10 | 11 | - (id)initWithData:(NSData *)data; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPDataResponse.m: -------------------------------------------------------------------------------- 1 | #import "HTTPDataResponse.h" 2 | #import "HTTPLogging.h" 3 | 4 | #if ! __has_feature(objc_arc) 5 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 6 | #endif 7 | 8 | // Log levels : off, error, warn, info, verbose 9 | // Other flags: trace 10 | static const int httpLogLevel = HTTP_LOG_LEVEL_OFF; // | HTTP_LOG_FLAG_TRACE; 11 | 12 | 13 | @implementation HTTPDataResponse 14 | 15 | - (id)initWithData:(NSData *)dataParam 16 | { 17 | if((self = [super init])) 18 | { 19 | HTTPLogTrace(); 20 | 21 | offset = 0; 22 | data = dataParam; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)dealloc 28 | { 29 | HTTPLogTrace(); 30 | 31 | } 32 | 33 | - (UInt64)contentLength 34 | { 35 | UInt64 result = (UInt64)[data length]; 36 | 37 | HTTPLogTrace2(@"%@[%p]: contentLength - %llu", THIS_FILE, self, result); 38 | 39 | return result; 40 | } 41 | 42 | - (UInt64)offset 43 | { 44 | HTTPLogTrace(); 45 | 46 | return offset; 47 | } 48 | 49 | - (void)setOffset:(UInt64)offsetParam 50 | { 51 | HTTPLogTrace2(@"%@[%p]: setOffset:%llu", THIS_FILE, self, offsetParam); 52 | 53 | offset = (NSUInteger)offsetParam; 54 | } 55 | 56 | - (NSData *)readDataOfLength:(NSUInteger)lengthParameter 57 | { 58 | HTTPLogTrace2(@"%@[%p]: readDataOfLength:%lu", THIS_FILE, self, (unsigned long)lengthParameter); 59 | 60 | NSUInteger remaining = [data length] - offset; 61 | NSUInteger length = lengthParameter < remaining ? lengthParameter : remaining; 62 | 63 | void *bytes = (void *)([data bytes] + offset); 64 | 65 | offset += length; 66 | 67 | return [NSData dataWithBytesNoCopy:bytes length:length freeWhenDone:NO]; 68 | } 69 | 70 | - (BOOL)isDone 71 | { 72 | BOOL result = (offset == [data length]); 73 | 74 | HTTPLogTrace2(@"%@[%p]: isDone - %@", THIS_FILE, self, (result ? @"YES" : @"NO")); 75 | 76 | return result; 77 | } 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPDynamicFileResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | #import "HTTPAsyncFileResponse.h" 4 | 5 | /** 6 | * This class is designed to assist with dynamic content. 7 | * Imagine you have a file that you want to make dynamic: 8 | * 9 | * 10 | * 11 | *

ComputerName Control Panel

12 | * ... 13 | *
  • System Time: SysTime
  • 14 | * 15 | * 16 | * 17 | * Now you could generate the entire file in Objective-C, 18 | * but this would be a horribly tedious process. 19 | * Beside, you want to design the file with professional tools to make it look pretty. 20 | * 21 | * So all you have to do is escape your dynamic content like this: 22 | * 23 | * ... 24 | *

    %%ComputerName%% Control Panel

    25 | * ... 26 | *
  • System Time: %%SysTime%%
  • 27 | * 28 | * And then you create an instance of this class with: 29 | * 30 | * - separator = @"%%" 31 | * - replacementDictionary = { "ComputerName"="Black MacBook", "SysTime"="2010-04-30 03:18:24" } 32 | * 33 | * This class will then perform the replacements for you, on the fly, as it reads the file data. 34 | * This class is also asynchronous, so it will perform the file IO using its own GCD queue. 35 | * 36 | * All keys for the replacementDictionary must be NSString's. 37 | * Values for the replacementDictionary may be NSString's, or any object that 38 | * returns what you want when its description method is invoked. 39 | **/ 40 | 41 | @interface HTTPDynamicFileResponse : HTTPAsyncFileResponse 42 | { 43 | NSData *separator; 44 | NSDictionary *replacementDict; 45 | } 46 | 47 | - (id)initWithFilePath:(NSString *)filePath 48 | forConnection:(HTTPConnection *)connection 49 | separator:(NSString *)separatorStr 50 | replacementDictionary:(NSDictionary *)dictionary; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPFileResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | 4 | @class HTTPConnection; 5 | 6 | 7 | @interface HTTPFileResponse : NSObject 8 | { 9 | HTTPConnection *connection; 10 | 11 | NSString *filePath; 12 | UInt64 fileLength; 13 | UInt64 fileOffset; 14 | 15 | BOOL aborted; 16 | 17 | int fileFD; 18 | void *buffer; 19 | NSUInteger bufferSize; 20 | } 21 | 22 | - (id)initWithFilePath:(NSString *)filePath forConnection:(HTTPConnection *)connection; 23 | - (NSString *)filePath; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPFileResponse.m: -------------------------------------------------------------------------------- 1 | #import "HTTPFileResponse.h" 2 | #import "HTTPConnection.h" 3 | #import "HTTPLogging.h" 4 | 5 | #import 6 | #import 7 | 8 | #if ! __has_feature(objc_arc) 9 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 10 | #endif 11 | 12 | // Log levels : off, error, warn, info, verbose 13 | // Other flags: trace 14 | static const int httpLogLevel = HTTP_LOG_LEVEL_WARN; // | HTTP_LOG_FLAG_TRACE; 15 | 16 | #define NULL_FD -1 17 | 18 | 19 | @implementation HTTPFileResponse 20 | 21 | - (id)initWithFilePath:(NSString *)fpath forConnection:(HTTPConnection *)parent 22 | { 23 | if((self = [super init])) 24 | { 25 | HTTPLogTrace(); 26 | 27 | connection = parent; // Parents retain children, children do NOT retain parents 28 | 29 | fileFD = NULL_FD; 30 | filePath = [[fpath copy] stringByResolvingSymlinksInPath]; 31 | if (filePath == nil) 32 | { 33 | HTTPLogWarn(@"%@: Init failed - Nil filePath", THIS_FILE); 34 | 35 | return nil; 36 | } 37 | 38 | NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil]; 39 | if (fileAttributes == nil) 40 | { 41 | HTTPLogWarn(@"%@: Init failed - Unable to get file attributes. filePath: %@", THIS_FILE, filePath); 42 | 43 | return nil; 44 | } 45 | 46 | fileLength = (UInt64)[[fileAttributes objectForKey:NSFileSize] unsignedLongLongValue]; 47 | fileOffset = 0; 48 | 49 | aborted = NO; 50 | 51 | // We don't bother opening the file here. 52 | // If this is a HEAD request we only need to know the fileLength. 53 | } 54 | return self; 55 | } 56 | 57 | - (void)abort 58 | { 59 | HTTPLogTrace(); 60 | 61 | [connection responseDidAbort:self]; 62 | aborted = YES; 63 | } 64 | 65 | - (BOOL)openFile 66 | { 67 | HTTPLogTrace(); 68 | 69 | fileFD = open([filePath UTF8String], O_RDONLY); 70 | if (fileFD == NULL_FD) 71 | { 72 | HTTPLogError(@"%@[%p]: Unable to open file. filePath: %@", THIS_FILE, self, filePath); 73 | 74 | [self abort]; 75 | return NO; 76 | } 77 | 78 | HTTPLogVerbose(@"%@[%p]: Open fd[%i] -> %@", THIS_FILE, self, fileFD, filePath); 79 | 80 | return YES; 81 | } 82 | 83 | - (BOOL)openFileIfNeeded 84 | { 85 | if (aborted) 86 | { 87 | // The file operation has been aborted. 88 | // This could be because we failed to open the file, 89 | // or the reading process failed. 90 | return NO; 91 | } 92 | 93 | if (fileFD != NULL_FD) 94 | { 95 | // File has already been opened. 96 | return YES; 97 | } 98 | 99 | return [self openFile]; 100 | } 101 | 102 | - (UInt64)contentLength 103 | { 104 | HTTPLogTrace(); 105 | 106 | return fileLength; 107 | } 108 | 109 | - (UInt64)offset 110 | { 111 | HTTPLogTrace(); 112 | 113 | return fileOffset; 114 | } 115 | 116 | - (void)setOffset:(UInt64)offset 117 | { 118 | HTTPLogTrace2(@"%@[%p]: setOffset:%llu", THIS_FILE, self, offset); 119 | 120 | if (![self openFileIfNeeded]) 121 | { 122 | // File opening failed, 123 | // or response has been aborted due to another error. 124 | return; 125 | } 126 | 127 | fileOffset = offset; 128 | 129 | off_t result = lseek(fileFD, (off_t)offset, SEEK_SET); 130 | if (result == -1) 131 | { 132 | HTTPLogError(@"%@[%p]: lseek failed - errno(%i) filePath(%@)", THIS_FILE, self, errno, filePath); 133 | 134 | [self abort]; 135 | } 136 | } 137 | 138 | - (NSData *)readDataOfLength:(NSUInteger)length 139 | { 140 | HTTPLogTrace2(@"%@[%p]: readDataOfLength:%lu", THIS_FILE, self, (unsigned long)length); 141 | 142 | if (![self openFileIfNeeded]) 143 | { 144 | // File opening failed, 145 | // or response has been aborted due to another error. 146 | return nil; 147 | } 148 | 149 | // Determine how much data we should read. 150 | // 151 | // It is OK if we ask to read more bytes than exist in the file. 152 | // It is NOT OK to over-allocate the buffer. 153 | 154 | UInt64 bytesLeftInFile = fileLength - fileOffset; 155 | 156 | NSUInteger bytesToRead = (NSUInteger)MIN(length, bytesLeftInFile); 157 | 158 | // Make sure buffer is big enough for read request. 159 | // Do not over-allocate. 160 | 161 | if (buffer == NULL || bufferSize < bytesToRead) 162 | { 163 | bufferSize = bytesToRead; 164 | buffer = reallocf(buffer, (size_t)bufferSize); 165 | 166 | if (buffer == NULL) 167 | { 168 | HTTPLogError(@"%@[%p]: Unable to allocate buffer", THIS_FILE, self); 169 | 170 | [self abort]; 171 | return nil; 172 | } 173 | } 174 | 175 | // Perform the read 176 | 177 | HTTPLogVerbose(@"%@[%p]: Attempting to read %lu bytes from file", THIS_FILE, self, (unsigned long)bytesToRead); 178 | 179 | ssize_t result = read(fileFD, buffer, bytesToRead); 180 | 181 | // Check the results 182 | 183 | if (result < 0) 184 | { 185 | HTTPLogError(@"%@: Error(%i) reading file(%@)", THIS_FILE, errno, filePath); 186 | 187 | [self abort]; 188 | return nil; 189 | } 190 | else if (result == 0) 191 | { 192 | HTTPLogError(@"%@: Read EOF on file(%@)", THIS_FILE, filePath); 193 | 194 | [self abort]; 195 | return nil; 196 | } 197 | else // (result > 0) 198 | { 199 | HTTPLogVerbose(@"%@[%p]: Read %ld bytes from file", THIS_FILE, self, (long)result); 200 | 201 | fileOffset += result; 202 | 203 | return [NSData dataWithBytes:buffer length:result]; 204 | } 205 | } 206 | 207 | - (BOOL)isDone 208 | { 209 | BOOL result = (fileOffset == fileLength); 210 | 211 | HTTPLogTrace2(@"%@[%p]: isDone - %@", THIS_FILE, self, (result ? @"YES" : @"NO")); 212 | 213 | return result; 214 | } 215 | 216 | - (NSString *)filePath 217 | { 218 | return filePath; 219 | } 220 | 221 | - (void)dealloc 222 | { 223 | HTTPLogTrace(); 224 | 225 | if (fileFD != NULL_FD) 226 | { 227 | HTTPLogVerbose(@"%@[%p]: Close fd[%i]", THIS_FILE, self, fileFD); 228 | 229 | close(fileFD); 230 | } 231 | 232 | if (buffer) 233 | free(buffer); 234 | 235 | } 236 | 237 | @end 238 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPRedirectResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | 4 | 5 | @interface HTTPRedirectResponse : NSObject 6 | { 7 | NSString *redirectPath; 8 | } 9 | 10 | - (id)initWithPath:(NSString *)redirectPath; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/Responses/HTTPRedirectResponse.m: -------------------------------------------------------------------------------- 1 | #import "HTTPRedirectResponse.h" 2 | #import "HTTPLogging.h" 3 | 4 | #if ! __has_feature(objc_arc) 5 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 6 | #endif 7 | 8 | // Log levels : off, error, warn, info, verbose 9 | // Other flags: trace 10 | static const int httpLogLevel = HTTP_LOG_LEVEL_OFF; // | HTTP_LOG_FLAG_TRACE; 11 | 12 | 13 | @implementation HTTPRedirectResponse 14 | 15 | - (id)initWithPath:(NSString *)path 16 | { 17 | if ((self = [super init])) 18 | { 19 | HTTPLogTrace(); 20 | 21 | redirectPath = [path copy]; 22 | } 23 | return self; 24 | } 25 | 26 | - (UInt64)contentLength 27 | { 28 | return 0; 29 | } 30 | 31 | - (UInt64)offset 32 | { 33 | return 0; 34 | } 35 | 36 | - (void)setOffset:(UInt64)offset 37 | { 38 | // Nothing to do 39 | } 40 | 41 | - (NSData *)readDataOfLength:(NSUInteger)length 42 | { 43 | HTTPLogTrace(); 44 | 45 | return nil; 46 | } 47 | 48 | - (BOOL)isDone 49 | { 50 | return YES; 51 | } 52 | 53 | - (NSDictionary *)httpHeaders 54 | { 55 | HTTPLogTrace(); 56 | 57 | return [NSDictionary dictionaryWithObject:redirectPath forKey:@"Location"]; 58 | } 59 | 60 | - (NSInteger)status 61 | { 62 | HTTPLogTrace(); 63 | 64 | return 302; 65 | } 66 | 67 | - (void)dealloc 68 | { 69 | HTTPLogTrace(); 70 | 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Core/WebSocket.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class HTTPMessage; 4 | @class GCDAsyncSocket; 5 | 6 | 7 | #define WebSocketDidDieNotification @"WebSocketDidDie" 8 | 9 | @interface WebSocket : NSObject 10 | { 11 | dispatch_queue_t websocketQueue; 12 | 13 | HTTPMessage *request; 14 | GCDAsyncSocket *asyncSocket; 15 | 16 | NSData *term; 17 | 18 | BOOL isStarted; 19 | BOOL isOpen; 20 | BOOL isVersion76; 21 | 22 | id __unsafe_unretained delegate; 23 | } 24 | 25 | + (BOOL)isWebSocketRequest:(HTTPMessage *)request; 26 | 27 | - (id)initWithRequest:(HTTPMessage *)request socket:(GCDAsyncSocket *)socket; 28 | 29 | /** 30 | * Delegate option. 31 | * 32 | * In most cases it will be easier to subclass WebSocket, 33 | * but some circumstances may lead one to prefer standard delegate callbacks instead. 34 | **/ 35 | @property (/* atomic */ unsafe_unretained) id delegate; 36 | 37 | /** 38 | * The WebSocket class is thread-safe, generally via it's GCD queue. 39 | * All public API methods are thread-safe, 40 | * and the subclass API methods are thread-safe as they are all invoked on the same GCD queue. 41 | **/ 42 | @property (nonatomic, readonly) dispatch_queue_t websocketQueue; 43 | 44 | /** 45 | * Public API 46 | * 47 | * These methods are automatically called by the HTTPServer. 48 | * You may invoke the stop method yourself to close the WebSocket manually. 49 | **/ 50 | - (void)start; 51 | - (void)stop; 52 | 53 | /** 54 | * Public API 55 | * 56 | * Sends a message over the WebSocket. 57 | * This method is thread-safe. 58 | **/ 59 | - (void)sendMessage:(NSString *)msg; 60 | 61 | /** 62 | * Subclass API 63 | * 64 | * These methods are designed to be overriden by subclasses. 65 | **/ 66 | - (void)didOpen; 67 | - (void)didReceiveMessage:(NSString *)msg; 68 | - (void)didClose; 69 | 70 | @end 71 | 72 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 73 | #pragma mark - 74 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 75 | 76 | /** 77 | * There are two ways to create your own custom WebSocket: 78 | * 79 | * - Subclass it and override the methods you're interested in. 80 | * - Use traditional delegate paradigm along with your own custom class. 81 | * 82 | * They both exist to allow for maximum flexibility. 83 | * In most cases it will be easier to subclass WebSocket. 84 | * However some circumstances may lead one to prefer standard delegate callbacks instead. 85 | * One such example, you're already subclassing another class, so subclassing WebSocket isn't an option. 86 | **/ 87 | 88 | @protocol WebSocketDelegate 89 | @optional 90 | 91 | - (void)webSocketDidOpen:(WebSocket *)ws; 92 | 93 | - (void)webSocket:(WebSocket *)ws didReceiveMessage:(NSString *)msg; 94 | 95 | - (void)webSocketDidClose:(WebSocket *)ws; 96 | 97 | @end -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/DAVConnection.h: -------------------------------------------------------------------------------- 1 | #import "HTTPConnection.h" 2 | 3 | @interface DAVConnection : HTTPConnection { 4 | id requestContentBody; 5 | NSOutputStream* requestContentStream; 6 | } 7 | @end 8 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/DAVResponse.h: -------------------------------------------------------------------------------- 1 | #import "HTTPResponse.h" 2 | 3 | @interface DAVResponse : NSObject { 4 | @private 5 | UInt64 _offset; 6 | NSMutableDictionary* _headers; 7 | NSData* _data; 8 | NSInteger _status; 9 | } 10 | - (id) initWithMethod:(NSString*)method headers:(NSDictionary*)headers bodyData:(NSData*)body resourcePath:(NSString*)resourcePath rootPath:(NSString*)rootPath; 11 | @end 12 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/DELETEResponse.h: -------------------------------------------------------------------------------- 1 | #import "HTTPResponse.h" 2 | 3 | @interface DELETEResponse : NSObject { 4 | NSInteger _status; 5 | } 6 | - (id) initWithFilePath:(NSString*)path; 7 | @end 8 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/DELETEResponse.m: -------------------------------------------------------------------------------- 1 | #import "DELETEResponse.h" 2 | #import "HTTPLogging.h" 3 | 4 | // HTTP methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html 5 | // HTTP headers: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 6 | // HTTP status codes: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 7 | 8 | static const int httpLogLevel = HTTP_LOG_LEVEL_WARN; 9 | 10 | @implementation DELETEResponse 11 | 12 | - (id) initWithFilePath:(NSString*)path { 13 | if ((self = [super init])) { 14 | BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path]; 15 | if ([[NSFileManager defaultManager] removeItemAtPath:path error:NULL]) { 16 | _status = exists ? 200 : 204; 17 | } else { 18 | HTTPLogError(@"Failed deleting \"%@\"", path); 19 | _status = 404; 20 | } 21 | } 22 | return self; 23 | } 24 | 25 | - (UInt64) contentLength { 26 | return 0; 27 | } 28 | 29 | - (UInt64) offset { 30 | return 0; 31 | } 32 | 33 | - (void)setOffset:(UInt64)offset { 34 | ; 35 | } 36 | 37 | - (NSData*) readDataOfLength:(NSUInteger)length { 38 | return nil; 39 | } 40 | 41 | - (BOOL) isDone { 42 | return YES; 43 | } 44 | 45 | - (NSInteger) status { 46 | return _status; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/PUTResponse.h: -------------------------------------------------------------------------------- 1 | #import "HTTPResponse.h" 2 | 3 | @interface PUTResponse : NSObject { 4 | NSInteger _status; 5 | } 6 | - (id) initWithFilePath:(NSString*)path headers:(NSDictionary*)headers bodyData:(NSData*)body; 7 | - (id) initWithFilePath:(NSString*)path headers:(NSDictionary*)headers bodyFile:(NSString*)body; 8 | @end 9 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Extensions/WebDAV/PUTResponse.m: -------------------------------------------------------------------------------- 1 | #import "PUTResponse.h" 2 | #import "HTTPLogging.h" 3 | 4 | // HTTP methods: http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html 5 | // HTTP headers: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html 6 | // HTTP status codes: http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 7 | 8 | static const int httpLogLevel = HTTP_LOG_LEVEL_WARN; 9 | 10 | @implementation PUTResponse 11 | 12 | - (id) initWithFilePath:(NSString*)path headers:(NSDictionary*)headers body:(id)body { 13 | if ((self = [super init])) { 14 | if ([headers objectForKey:@"Content-Range"]) { 15 | HTTPLogError(@"Content-Range not supported for upload to \"%@\"", path); 16 | _status = 400; 17 | } else { 18 | BOOL overwrite = [[NSFileManager defaultManager] fileExistsAtPath:path]; 19 | BOOL success; 20 | if ([body isKindOfClass:[NSString class]]) { 21 | [[NSFileManager defaultManager] removeItemAtPath:path error:NULL]; 22 | success = [[NSFileManager defaultManager] moveItemAtPath:body toPath:path error:NULL]; 23 | } else { 24 | success = [body writeToFile:path atomically:YES]; 25 | } 26 | if (success) { 27 | _status = overwrite ? 200 : 201; 28 | } else { 29 | HTTPLogError(@"Failed writing upload to \"%@\"", path); 30 | _status = 403; 31 | } 32 | } 33 | } 34 | return self; 35 | } 36 | 37 | - (id) initWithFilePath:(NSString*)path headers:(NSDictionary*)headers bodyData:(NSData*)body { 38 | return [self initWithFilePath:path headers:headers body:body]; 39 | } 40 | 41 | - (id) initWithFilePath:(NSString*)path headers:(NSDictionary*)headers bodyFile:(NSString*)body { 42 | return [self initWithFilePath:path headers:headers body:body]; 43 | } 44 | 45 | - (UInt64) contentLength { 46 | return 0; 47 | } 48 | 49 | - (UInt64) offset { 50 | return 0; 51 | } 52 | 53 | - (void) setOffset:(UInt64)offset { 54 | ; 55 | } 56 | 57 | - (NSData*) readDataOfLength:(NSUInteger)length { 58 | return nil; 59 | } 60 | 61 | - (BOOL) isDone { 62 | return YES; 63 | } 64 | 65 | - (NSInteger) status { 66 | return _status; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /CocoaHTTPServer/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2011, Deusty, LLC 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, 7 | with or without modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Neither the name of Deusty nor the names of its 14 | contributors may be used to endorse or promote products 15 | derived from this software without specific prior 16 | written permission of Deusty, LLC. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /CocoaHTTPServer/README.markdown: -------------------------------------------------------------------------------- 1 | CocoaHTTPServer is a small, lightweight, embeddable HTTP server for Mac OS X or iOS applications. 2 | 3 | Sometimes developers need an embedded HTTP server in their app. Perhaps it's a server application with remote monitoring. Or perhaps it's a desktop application using HTTP for the communication backend. Or perhaps it's an iOS app providing over-the-air access to documents. Whatever your reason, CocoaHTTPServer can get the job done. It provides: 4 | 5 | - Built in support for bonjour broadcasting 6 | - IPv4 and IPv6 support 7 | - Asynchronous networking using GCD and standard sockets 8 | - Password protection support 9 | - SSL/TLS encryption support 10 | - Extremely FAST and memory efficient 11 | - Extremely scalable (built entirely upon GCD) 12 | - Heavily commented code 13 | - Very easily extensible 14 | - WebDAV is supported too! 15 | 16 |
    17 | Can't find the answer to your question in any of the [wiki](https://github.com/robbiehanson/CocoaHTTPServer/wiki) articles? Try the **[mailing list](http://groups.google.com/group/cocoahttpserver)**. 18 |
    19 |
    20 | Love the project? Wanna buy me a coffee? (or a beer :D) [![donation](http://www.paypal.com/en_US/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=BHF2DJRETGV5S) 21 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaAsyncSocket/About.txt: -------------------------------------------------------------------------------- 1 | The CocoaAsyncSocket project is under Public Domain license. 2 | http://code.google.com/p/cocoaasyncsocket/ 3 | 4 | The AsyncSocket project has been around since 2001 and is used in many applications and frameworks. -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/About.txt: -------------------------------------------------------------------------------- 1 | CocoaLumberjack is under the New BSD License. 2 | https://github.com/robbiehanson/CocoaLumberjack 3 | 4 | Extensive documentation, tutorials, etc are available: 5 | https://github.com/robbiehanson/CocoaLumberjack/wiki 6 | 7 | Overview of the project (copied from google code homepage): 8 | 9 | 10 | 11 | The lumberjack framework is fast & simple, yet powerful & flexible. 12 | It is similar in concept to other popular logging frameworks such as log4j, yet is designed specifically for objective-c, and takes advantage of features such as multi-threading, grand central dispatch (if available), lockless atomic operations, and the dynamic nature of the objective-c runtime. 13 | 14 | Lumberjack is fast: 15 | In most cases it is an order of magnitude faster than NSLog. 16 | 17 | Lumberjack is simple: 18 | It takes as little as a single line of code to configure lumberjack when your application launches. Then simply replace your NSLog statements with DDLog statements and that's about it. (And the DDLog macros have the exact same format and syntax as NSLog, so it's super easy.) 19 | 20 | Lumberjack is powerful: 21 | One log statement can be sent to multiple loggers, meaning you can log to a file and the console simultaneously. Want more? Create your own loggers (it's easy) and send your log statements over the network. Or to a database or distributed file system. The sky is the limit. 22 | 23 | Lumberjack is flexible: 24 | Configure your logging however you want. Change log levels per file (perfect for debugging). Change log levels per logger (verbose console, but concise log file). Change log levels per xcode configuration (verbose debug, but concise release). Have your log statements compiled out of the release build. Customize the number of log levels for your application. Add your own fine-grained logging. Dynamically change log levels during runtime. Choose how & when you want your log files to be rolled. Upload your log files to a central server. Compress archived log files to save disk space... 25 | 26 | 27 | 28 | This framework is for you if: 29 | 30 | You're looking for a way to track down that impossible-to-reproduce bug that keeps popping up in the field. 31 | You're frustrated with the super short console log on the iPhone. 32 | You're looking to take your application to the next level in terms of support and stability. 33 | You're looking for an enterprise level logging solution for your application (Mac or iPhone). -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/DDASLLogger.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | #import "DDLog.h" 5 | 6 | /** 7 | * Welcome to Cocoa Lumberjack! 8 | * 9 | * The project page has a wealth of documentation if you have any questions. 10 | * https://github.com/robbiehanson/CocoaLumberjack 11 | * 12 | * If you're new to the project you may wish to read the "Getting Started" wiki. 13 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 14 | * 15 | * 16 | * This class provides a logger for the Apple System Log facility. 17 | * 18 | * As described in the "Getting Started" page, 19 | * the traditional NSLog() function directs it's output to two places: 20 | * 21 | * - Apple System Log 22 | * - StdErr (if stderr is a TTY) so log statements show up in Xcode console 23 | * 24 | * To duplicate NSLog() functionality you can simply add this logger and a tty logger. 25 | * However, if you instead choose to use file logging (for faster performance), 26 | * you may choose to use a file logger and a tty logger. 27 | **/ 28 | 29 | @interface DDASLLogger : DDAbstractLogger 30 | { 31 | aslclient client; 32 | } 33 | 34 | + (DDASLLogger *)sharedInstance; 35 | 36 | // Inherited from DDAbstractLogger 37 | 38 | // - (id )logFormatter; 39 | // - (void)setLogFormatter:(id )formatter; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/DDASLLogger.m: -------------------------------------------------------------------------------- 1 | #import "DDASLLogger.h" 2 | 3 | #import 4 | 5 | /** 6 | * Welcome to Cocoa Lumberjack! 7 | * 8 | * The project page has a wealth of documentation if you have any questions. 9 | * https://github.com/robbiehanson/CocoaLumberjack 10 | * 11 | * If you're new to the project you may wish to read the "Getting Started" wiki. 12 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 13 | **/ 14 | 15 | #if ! __has_feature(objc_arc) 16 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 17 | #endif 18 | 19 | 20 | @implementation DDASLLogger 21 | 22 | static DDASLLogger *sharedInstance; 23 | 24 | /** 25 | * The runtime sends initialize to each class in a program exactly one time just before the class, 26 | * or any class that inherits from it, is sent its first message from within the program. (Thus the 27 | * method may never be invoked if the class is not used.) The runtime sends the initialize message to 28 | * classes in a thread-safe manner. Superclasses receive this message before their subclasses. 29 | * 30 | * This method may also be called directly (assumably by accident), hence the safety mechanism. 31 | **/ 32 | + (void)initialize 33 | { 34 | static BOOL initialized = NO; 35 | if (!initialized) 36 | { 37 | initialized = YES; 38 | 39 | sharedInstance = [[DDASLLogger alloc] init]; 40 | } 41 | } 42 | 43 | + (DDASLLogger *)sharedInstance 44 | { 45 | return sharedInstance; 46 | } 47 | 48 | - (id)init 49 | { 50 | if (sharedInstance != nil) 51 | { 52 | return nil; 53 | } 54 | 55 | if ((self = [super init])) 56 | { 57 | // A default asl client is provided for the main thread, 58 | // but background threads need to create their own client. 59 | 60 | client = asl_open(NULL, "com.apple.console", 0); 61 | } 62 | return self; 63 | } 64 | 65 | - (void)logMessage:(DDLogMessage *)logMessage 66 | { 67 | NSString *logMsg = logMessage->logMsg; 68 | 69 | if (formatter) 70 | { 71 | logMsg = [formatter formatLogMessage:logMessage]; 72 | } 73 | 74 | if (logMsg) 75 | { 76 | const char *msg = [logMsg UTF8String]; 77 | 78 | int aslLogLevel; 79 | switch (logMessage->logLevel) 80 | { 81 | // Note: By default ASL will filter anything above level 5 (Notice). 82 | // So our mappings shouldn't go above that level. 83 | 84 | case 1 : aslLogLevel = ASL_LEVEL_CRIT; break; 85 | case 2 : aslLogLevel = ASL_LEVEL_ERR; break; 86 | case 3 : aslLogLevel = ASL_LEVEL_WARNING; break; 87 | default : aslLogLevel = ASL_LEVEL_NOTICE; break; 88 | } 89 | 90 | asl_log(client, NULL, aslLogLevel, "%s", msg); 91 | } 92 | } 93 | 94 | - (NSString *)loggerName 95 | { 96 | return @"cocoa.lumberjack.aslLogger"; 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/DDAbstractDatabaseLogger.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "DDLog.h" 4 | 5 | /** 6 | * Welcome to Cocoa Lumberjack! 7 | * 8 | * The project page has a wealth of documentation if you have any questions. 9 | * https://github.com/robbiehanson/CocoaLumberjack 10 | * 11 | * If you're new to the project you may wish to read the "Getting Started" wiki. 12 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 13 | * 14 | * 15 | * This class provides an abstract implementation of a database logger. 16 | * 17 | * That is, it provides the base implementation for a database logger to build atop of. 18 | * All that is needed for a concrete database logger is to extend this class 19 | * and override the methods in the implementation file that are prefixed with "db_". 20 | **/ 21 | 22 | @interface DDAbstractDatabaseLogger : DDAbstractLogger { 23 | @protected 24 | NSUInteger saveThreshold; 25 | NSTimeInterval saveInterval; 26 | NSTimeInterval maxAge; 27 | NSTimeInterval deleteInterval; 28 | BOOL deleteOnEverySave; 29 | 30 | BOOL saveTimerSuspended; 31 | NSUInteger unsavedCount; 32 | dispatch_time_t unsavedTime; 33 | dispatch_source_t saveTimer; 34 | dispatch_time_t lastDeleteTime; 35 | dispatch_source_t deleteTimer; 36 | } 37 | 38 | /** 39 | * Specifies how often to save the data to disk. 40 | * Since saving is an expensive operation (disk io) it is not done after every log statement. 41 | * These properties allow you to configure how/when the logger saves to disk. 42 | * 43 | * A save is done when either (whichever happens first): 44 | * 45 | * - The number of unsaved log entries reaches saveThreshold 46 | * - The amount of time since the oldest unsaved log entry was created reaches saveInterval 47 | * 48 | * You can optionally disable the saveThreshold by setting it to zero. 49 | * If you disable the saveThreshold you are entirely dependent on the saveInterval. 50 | * 51 | * You can optionally disable the saveInterval by setting it to zero (or a negative value). 52 | * If you disable the saveInterval you are entirely dependent on the saveThreshold. 53 | * 54 | * It's not wise to disable both saveThreshold and saveInterval. 55 | * 56 | * The default saveThreshold is 500. 57 | * The default saveInterval is 60 seconds. 58 | **/ 59 | @property (assign, readwrite) NSUInteger saveThreshold; 60 | @property (assign, readwrite) NSTimeInterval saveInterval; 61 | 62 | /** 63 | * It is likely you don't want the log entries to persist forever. 64 | * Doing so would allow the database to grow infinitely large over time. 65 | * 66 | * The maxAge property provides a way to specify how old a log statement can get 67 | * before it should get deleted from the database. 68 | * 69 | * The deleteInterval specifies how often to sweep for old log entries. 70 | * Since deleting is an expensive operation (disk io) is is done on a fixed interval. 71 | * 72 | * An alternative to the deleteInterval is the deleteOnEverySave option. 73 | * This specifies that old log entries should be deleted during every save operation. 74 | * 75 | * You can optionally disable the maxAge by setting it to zero (or a negative value). 76 | * If you disable the maxAge then old log statements are not deleted. 77 | * 78 | * You can optionally disable the deleteInterval by setting it to zero (or a negative value). 79 | * 80 | * If you disable both deleteInterval and deleteOnEverySave then old log statements are not deleted. 81 | * 82 | * It's not wise to enable both deleteInterval and deleteOnEverySave. 83 | * 84 | * The default maxAge is 7 days. 85 | * The default deleteInterval is 5 minutes. 86 | * The default deleteOnEverySave is NO. 87 | **/ 88 | @property (assign, readwrite) NSTimeInterval maxAge; 89 | @property (assign, readwrite) NSTimeInterval deleteInterval; 90 | @property (assign, readwrite) BOOL deleteOnEverySave; 91 | 92 | /** 93 | * Forces a save of any pending log entries (flushes log entries to disk). 94 | **/ 95 | - (void)savePendingLogEntries; 96 | 97 | /** 98 | * Removes any log entries that are older than maxAge. 99 | **/ 100 | - (void)deleteOldLogEntries; 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/DDTTYLogger.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "DDLog.h" 4 | 5 | /** 6 | * Welcome to Cocoa Lumberjack! 7 | * 8 | * The project page has a wealth of documentation if you have any questions. 9 | * https://github.com/robbiehanson/CocoaLumberjack 10 | * 11 | * If you're new to the project you may wish to read the "Getting Started" wiki. 12 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 13 | * 14 | * 15 | * This class provides a logger for Terminal output or Xcode console output, 16 | * depending on where you are running your code. 17 | * 18 | * As described in the "Getting Started" page, 19 | * the traditional NSLog() function directs it's output to two places: 20 | * 21 | * - Apple System Log (so it shows up in Console.app) 22 | * - StdErr (if stderr is a TTY, so log statements show up in Xcode console) 23 | * 24 | * To duplicate NSLog() functionality you can simply add this logger and an asl logger. 25 | * However, if you instead choose to use file logging (for faster performance), 26 | * you may choose to use only a file logger and a tty logger. 27 | **/ 28 | 29 | @interface DDTTYLogger : DDAbstractLogger 30 | { 31 | BOOL isaTTY; 32 | 33 | NSDateFormatter *dateFormatter; 34 | 35 | char *app; // Not null terminated 36 | char *pid; // Not null terminated 37 | 38 | size_t appLen; 39 | size_t pidLen; 40 | } 41 | 42 | + (DDTTYLogger *)sharedInstance; 43 | 44 | // Inherited from DDAbstractLogger 45 | 46 | // - (id )logFormatter; 47 | // - (void)setLogFormatter:(id )formatter; 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/DDTTYLogger.m: -------------------------------------------------------------------------------- 1 | #import "DDTTYLogger.h" 2 | 3 | #import 4 | #import 5 | 6 | /** 7 | * Welcome to Cocoa Lumberjack! 8 | * 9 | * The project page has a wealth of documentation if you have any questions. 10 | * https://github.com/robbiehanson/CocoaLumberjack 11 | * 12 | * If you're new to the project you may wish to read the "Getting Started" wiki. 13 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 14 | **/ 15 | 16 | #if ! __has_feature(objc_arc) 17 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 18 | #endif 19 | 20 | 21 | @implementation DDTTYLogger 22 | 23 | static DDTTYLogger *sharedInstance; 24 | 25 | /** 26 | * The runtime sends initialize to each class in a program exactly one time just before the class, 27 | * or any class that inherits from it, is sent its first message from within the program. (Thus the 28 | * method may never be invoked if the class is not used.) The runtime sends the initialize message to 29 | * classes in a thread-safe manner. Superclasses receive this message before their subclasses. 30 | * 31 | * This method may also be called directly (assumably by accident), hence the safety mechanism. 32 | **/ 33 | + (void)initialize 34 | { 35 | static BOOL initialized = NO; 36 | if (!initialized) 37 | { 38 | initialized = YES; 39 | 40 | sharedInstance = [[DDTTYLogger alloc] init]; 41 | } 42 | } 43 | 44 | + (DDTTYLogger *)sharedInstance 45 | { 46 | return sharedInstance; 47 | } 48 | 49 | - (id)init 50 | { 51 | if (sharedInstance != nil) 52 | { 53 | return nil; 54 | } 55 | 56 | if ((self = [super init])) 57 | { 58 | isaTTY = isatty(STDERR_FILENO); 59 | 60 | if (isaTTY) 61 | { 62 | dateFormatter = [[NSDateFormatter alloc] init]; 63 | [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; 64 | [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"]; 65 | 66 | // Initialze 'app' variable (char *) 67 | 68 | NSString *appNStr = [[NSProcessInfo processInfo] processName]; 69 | const char *appCStr = [appNStr UTF8String]; 70 | 71 | appLen = strlen(appCStr); 72 | 73 | app = (char *)malloc(appLen); 74 | strncpy(app, appCStr, appLen); // Not null terminated 75 | 76 | // Initialize 'pid' variable (char *) 77 | 78 | NSString *pidNStr = [NSString stringWithFormat:@"%i", (int)getpid()]; 79 | const char *pidCStr = [pidNStr UTF8String]; 80 | 81 | pidLen = strlen(pidCStr); 82 | 83 | pid = (char *)malloc(pidLen); 84 | strncpy(pid, pidCStr, pidLen); // Not null terminated 85 | } 86 | } 87 | return self; 88 | } 89 | 90 | - (void)logMessage:(DDLogMessage *)logMessage 91 | { 92 | if (!isaTTY) return; 93 | 94 | NSString *logMsg = logMessage->logMsg; 95 | BOOL isFormatted = NO; 96 | 97 | if (formatter) 98 | { 99 | logMsg = [formatter formatLogMessage:logMessage]; 100 | isFormatted = logMsg != logMessage->logMsg; 101 | } 102 | 103 | if (logMsg) 104 | { 105 | const char *msg = [logMsg UTF8String]; 106 | size_t msgLen = strlen(msg); 107 | 108 | if (isFormatted) 109 | { 110 | struct iovec v[2]; 111 | 112 | v[0].iov_base = (char *)msg; 113 | v[0].iov_len = msgLen; 114 | 115 | v[1].iov_base = "\n"; 116 | v[1].iov_len = (msg[msgLen] == '\n') ? 0 : 1; 117 | 118 | writev(STDERR_FILENO, v, 2); 119 | } 120 | else 121 | { 122 | // The following is a highly optimized verion of file output to std err. 123 | 124 | // ts = timestamp 125 | 126 | NSString *tsNStr = [dateFormatter stringFromDate:(logMessage->timestamp)]; 127 | 128 | const char *tsCStr = [tsNStr UTF8String]; 129 | size_t tsLen = strlen(tsCStr); 130 | 131 | // tid = thread id 132 | // 133 | // How many characters do we need for the thread id? 134 | // logMessage->machThreadID is of type mach_port_t, which is an unsigned int. 135 | // 136 | // 1 hex char = 4 bits 137 | // 8 hex chars for 32 bit, plus ending '\0' = 9 138 | 139 | char tidCStr[9]; 140 | int tidLen = snprintf(tidCStr, 9, "%x", logMessage->machThreadID); 141 | 142 | // Here is our format: "%s %s[%i:%s] %s", timestamp, appName, processID, threadID, logMsg 143 | 144 | struct iovec v[10]; 145 | 146 | v[0].iov_base = (char *)tsCStr; 147 | v[0].iov_len = tsLen; 148 | 149 | v[1].iov_base = " "; 150 | v[1].iov_len = 1; 151 | 152 | v[2].iov_base = app; 153 | v[2].iov_len = appLen; 154 | 155 | v[3].iov_base = "["; 156 | v[3].iov_len = 1; 157 | 158 | v[4].iov_base = pid; 159 | v[4].iov_len = pidLen; 160 | 161 | v[5].iov_base = ":"; 162 | v[5].iov_len = 1; 163 | 164 | v[6].iov_base = tidCStr; 165 | v[6].iov_len = MIN((size_t)8, tidLen); // snprintf doesn't return what you might think 166 | 167 | v[7].iov_base = "] "; 168 | v[7].iov_len = 2; 169 | 170 | v[8].iov_base = (char *)msg; 171 | v[8].iov_len = msgLen; 172 | 173 | v[9].iov_base = "\n"; 174 | v[9].iov_len = (msg[msgLen] == '\n') ? 0 : 1; 175 | 176 | writev(STDERR_FILENO, v, 10); 177 | } 178 | } 179 | } 180 | 181 | - (NSString *)loggerName 182 | { 183 | return @"cocoa.lumberjack.ttyLogger"; 184 | } 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/Extensions/ContextFilterLogFormatter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "DDLog.h" 3 | 4 | @class ContextFilterLogFormatter; 5 | 6 | /** 7 | * Welcome to Cocoa Lumberjack! 8 | * 9 | * The project page has a wealth of documentation if you have any questions. 10 | * https://github.com/robbiehanson/CocoaLumberjack 11 | * 12 | * If you're new to the project you may wish to read the "Getting Started" page. 13 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 14 | * 15 | * 16 | * This class provides a log formatter that filters log statements from a logging context not on the whitelist. 17 | * 18 | * A log formatter can be added to any logger to format and/or filter its output. 19 | * You can learn more about log formatters here: 20 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters 21 | * 22 | * You can learn more about logging context's here: 23 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomContext 24 | * 25 | * But here's a quick overview / refresher: 26 | * 27 | * Every log statement has a logging context. 28 | * These come from the underlying logging macros defined in DDLog.h. 29 | * The default logging context is zero. 30 | * You can define multiple logging context's for use in your application. 31 | * For example, logically separate parts of your app each have a different logging context. 32 | * Also 3rd party frameworks that make use of Lumberjack generally use their own dedicated logging context. 33 | **/ 34 | @interface ContextWhitelistFilterLogFormatter : NSObject 35 | 36 | - (id)init; 37 | 38 | - (void)addToWhitelist:(int)loggingContext; 39 | - (void)removeFromWhitelist:(int)loggingContext; 40 | 41 | - (NSArray *)whitelist; 42 | 43 | - (BOOL)isOnWhitelist:(int)loggingContext; 44 | 45 | @end 46 | 47 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 48 | #pragma mark - 49 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 50 | 51 | /** 52 | * This class provides a log formatter that filters log statements from a logging context on the blacklist. 53 | **/ 54 | @interface ContextBlacklistFilterLogFormatter : NSObject 55 | 56 | - (id)init; 57 | 58 | - (void)addToBlacklist:(int)loggingContext; 59 | - (void)removeFromBlacklist:(int)loggingContext; 60 | 61 | - (NSArray *)blacklist; 62 | 63 | - (BOOL)isOnBlacklist:(int)loggingContext; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/Extensions/ContextFilterLogFormatter.m: -------------------------------------------------------------------------------- 1 | #import "ContextFilterLogFormatter.h" 2 | #import 3 | 4 | /** 5 | * Welcome to Cocoa Lumberjack! 6 | * 7 | * The project page has a wealth of documentation if you have any questions. 8 | * https://github.com/robbiehanson/CocoaLumberjack 9 | * 10 | * If you're new to the project you may wish to read the "Getting Started" wiki. 11 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 12 | **/ 13 | 14 | #if ! __has_feature(objc_arc) 15 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 16 | #endif 17 | 18 | @interface LoggingContextSet : NSObject 19 | 20 | - (void)addToSet:(int)loggingContext; 21 | - (void)removeFromSet:(int)loggingContext; 22 | 23 | - (NSArray *)currentSet; 24 | 25 | - (BOOL)isInSet:(int)loggingContext; 26 | 27 | @end 28 | 29 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 30 | #pragma mark - 31 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 32 | 33 | @implementation ContextWhitelistFilterLogFormatter 34 | { 35 | LoggingContextSet *contextSet; 36 | } 37 | 38 | - (id)init 39 | { 40 | if ((self = [super init])) 41 | { 42 | contextSet = [[LoggingContextSet alloc] init]; 43 | } 44 | return self; 45 | } 46 | 47 | 48 | - (void)addToWhitelist:(int)loggingContext 49 | { 50 | [contextSet addToSet:loggingContext]; 51 | } 52 | 53 | - (void)removeFromWhitelist:(int)loggingContext 54 | { 55 | [contextSet removeFromSet:loggingContext]; 56 | } 57 | 58 | - (NSArray *)whitelist 59 | { 60 | return [contextSet currentSet]; 61 | } 62 | 63 | - (BOOL)isOnWhitelist:(int)loggingContext 64 | { 65 | return [contextSet isInSet:loggingContext]; 66 | } 67 | 68 | - (NSString *)formatLogMessage:(DDLogMessage *)logMessage 69 | { 70 | if ([self isOnWhitelist:logMessage->logContext]) 71 | return logMessage->logMsg; 72 | else 73 | return nil; 74 | } 75 | 76 | @end 77 | 78 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 79 | #pragma mark - 80 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 81 | 82 | @implementation ContextBlacklistFilterLogFormatter 83 | { 84 | LoggingContextSet *contextSet; 85 | } 86 | 87 | - (id)init 88 | { 89 | if ((self = [super init])) 90 | { 91 | contextSet = [[LoggingContextSet alloc] init]; 92 | } 93 | return self; 94 | } 95 | 96 | 97 | - (void)addToBlacklist:(int)loggingContext 98 | { 99 | [contextSet addToSet:loggingContext]; 100 | } 101 | 102 | - (void)removeFromBlacklist:(int)loggingContext 103 | { 104 | [contextSet removeFromSet:loggingContext]; 105 | } 106 | 107 | - (NSArray *)blacklist 108 | { 109 | return [contextSet currentSet]; 110 | } 111 | 112 | - (BOOL)isOnBlacklist:(int)loggingContext 113 | { 114 | return [contextSet isInSet:loggingContext]; 115 | } 116 | 117 | - (NSString *)formatLogMessage:(DDLogMessage *)logMessage 118 | { 119 | if ([self isOnBlacklist:logMessage->logContext]) 120 | return nil; 121 | else 122 | return logMessage->logMsg; 123 | } 124 | 125 | @end 126 | 127 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 128 | #pragma mark - 129 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 130 | 131 | @implementation LoggingContextSet 132 | { 133 | OSSpinLock lock; 134 | NSMutableSet *set; 135 | } 136 | 137 | - (id)init 138 | { 139 | if ((self = [super init])) 140 | { 141 | set = [[NSMutableSet alloc] init]; 142 | } 143 | return self; 144 | } 145 | 146 | 147 | - (void)addToSet:(int)loggingContext 148 | { 149 | OSSpinLockLock(&lock); 150 | { 151 | [set addObject:[NSNumber numberWithInt:loggingContext]]; 152 | } 153 | OSSpinLockUnlock(&lock); 154 | } 155 | 156 | - (void)removeFromSet:(int)loggingContext 157 | { 158 | OSSpinLockLock(&lock); 159 | { 160 | [set removeObject:[NSNumber numberWithInt:loggingContext]]; 161 | } 162 | OSSpinLockUnlock(&lock); 163 | } 164 | 165 | - (NSArray *)currentSet 166 | { 167 | NSArray *result = nil; 168 | 169 | OSSpinLockLock(&lock); 170 | { 171 | result = [set allObjects]; 172 | } 173 | OSSpinLockUnlock(&lock); 174 | 175 | return result; 176 | } 177 | 178 | - (BOOL)isInSet:(int)loggingContext 179 | { 180 | BOOL result = NO; 181 | 182 | OSSpinLockLock(&lock); 183 | { 184 | result = [set containsObject:[NSNumber numberWithInt:loggingContext]]; 185 | } 186 | OSSpinLockUnlock(&lock); 187 | 188 | return result; 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "DDLog.h" 4 | 5 | 6 | /** 7 | * Welcome to Cocoa Lumberjack! 8 | * 9 | * The project page has a wealth of documentation if you have any questions. 10 | * https://github.com/robbiehanson/CocoaLumberjack 11 | * 12 | * If you're new to the project you may wish to read the "Getting Started" page. 13 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 14 | * 15 | * 16 | * This class provides a log formatter that prints the dispatch_queue label instead of the mach_thread_id. 17 | * 18 | * A log formatter can be added to any logger to format and/or filter its output. 19 | * You can learn more about log formatters here: 20 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters 21 | * 22 | * A typical NSLog (or DDTTYLogger) prints detailed info as [:]. 23 | * For example: 24 | * 25 | * 2011-10-17 20:21:45.435 AppName[19928:5207] Your log message here 26 | * 27 | * Where: 28 | * - 19928 = process id 29 | * - 5207 = thread id (mach_thread_id printed in hex) 30 | * 31 | * When using grand central dispatch (GCD), this information is less useful. 32 | * This is because a single serial dispatch queue may be run on any thread from an internally managed thread pool. 33 | * For example: 34 | * 35 | * 2011-10-17 20:32:31.111 AppName[19954:4d07] Message from my_serial_dispatch_queue 36 | * 2011-10-17 20:32:31.112 AppName[19954:5207] Message from my_serial_dispatch_queue 37 | * 2011-10-17 20:32:31.113 AppName[19954:2c55] Message from my_serial_dispatch_queue 38 | * 39 | * This formatter allows you to replace the standard [box:info] with the dispatch_queue name. 40 | * For example: 41 | * 42 | * 2011-10-17 20:32:31.111 AppName[img-scaling] Message from my_serial_dispatch_queue 43 | * 2011-10-17 20:32:31.112 AppName[img-scaling] Message from my_serial_dispatch_queue 44 | * 2011-10-17 20:32:31.113 AppName[img-scaling] Message from my_serial_dispatch_queue 45 | * 46 | * If the dispatch_queue doesn't have a set name, then it falls back to the thread name. 47 | * If the current thread doesn't have a set name, then it falls back to the mach_thread_id in hex (like normal). 48 | * 49 | * Note: If manually creating your own background threads (via NSThread/alloc/init or NSThread/detachNeThread), 50 | * you can use [[NSThread currentThread] setName:(NSString *)]. 51 | **/ 52 | @interface DispatchQueueLogFormatter : NSObject 53 | { 54 | @protected 55 | 56 | NSDateFormatter *dateFormatter; 57 | 58 | @private 59 | 60 | OSSpinLock lock; 61 | 62 | NSUInteger _minQueueLength; // _prefix == Only access via atomic property 63 | NSUInteger _maxQueueLength; // _prefix == Only access via atomic property 64 | NSMutableDictionary *_replacements; // _prefix == Only access from within spinlock 65 | } 66 | 67 | /** 68 | * Standard init method. 69 | * Configure using properties as desired. 70 | **/ 71 | - (id)init; 72 | 73 | /** 74 | * The minQueueLength restricts the minimum size of the [detail box]. 75 | * If the minQueueLength is set to 0, there is no restriction. 76 | * 77 | * For example, say a dispatch_queue has a label of "diskIO": 78 | * 79 | * If the minQueueLength is 0: [diskIO] 80 | * If the minQueueLength is 4: [diskIO] 81 | * If the minQueueLength is 5: [diskIO] 82 | * If the minQueueLength is 6: [diskIO] 83 | * If the minQueueLength is 7: [diskIO ] 84 | * If the minQueueLength is 8: [diskIO ] 85 | * 86 | * The default minQueueLength is 0 (no minimum, so [detail box] won't be padded). 87 | **/ 88 | @property (assign) NSUInteger minQueueLength; 89 | 90 | /** 91 | * The maxQueueLength restricts the number of characters that will be inside the [detail box]. 92 | * If the maxQueueLength is 0, there is no restriction. 93 | * For example: 94 | * 95 | * Say a dispatch_queue has a label of "diskIO". (standardizedQueueLength==NO) 96 | * If the maxQueueLength is 0: [diskIO] 97 | * If the maxQueueLength is 4: [disk] 98 | * If the maxQueueLength is 5: [diskI] 99 | * If the maxQueueLength is 6: [diskIO] 100 | * If the maxQueueLength is 7: [diskIO] 101 | * If the maxQueueLength is 8: [diskIO] 102 | * 103 | * The default maxQueueLength is 0 (no maximum, so [thread box] queue names won't be truncated). 104 | **/ 105 | @property (assign) NSUInteger maxQueueLength; 106 | 107 | /** 108 | * Sometimes queue labels have long names like "com.apple.main-queue", 109 | * but you'd prefer something shorter like simply "main". 110 | * 111 | * This method allows you to set such preferred replacements. 112 | * The above example is set by default. 113 | * 114 | * To remove/undo a previous replacement, invoke this method with nil for the 'shortLabel' parameter. 115 | **/ 116 | - (NSString *)replacementStringForQueueLabel:(NSString *)longLabel; 117 | - (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel; 118 | 119 | @end 120 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/Extensions/DispatchQueueLogFormatter.m: -------------------------------------------------------------------------------- 1 | #import "DispatchQueueLogFormatter.h" 2 | 3 | /** 4 | * Welcome to Cocoa Lumberjack! 5 | * 6 | * The project page has a wealth of documentation if you have any questions. 7 | * https://github.com/robbiehanson/CocoaLumberjack 8 | * 9 | * If you're new to the project you may wish to read the "Getting Started" wiki. 10 | * https://github.com/robbiehanson/CocoaLumberjack/wiki/GettingStarted 11 | **/ 12 | 13 | #if ! __has_feature(objc_arc) 14 | #warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC). 15 | #endif 16 | 17 | 18 | @implementation DispatchQueueLogFormatter 19 | 20 | - (id)init 21 | { 22 | if ((self = [super init])) 23 | { 24 | dateFormatter = [[NSDateFormatter alloc] init]; 25 | [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4]; 26 | [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss:SSS"]; 27 | 28 | _minQueueLength = 0; 29 | _maxQueueLength = 0; 30 | _replacements = [[NSMutableDictionary alloc] init]; 31 | 32 | // Set default replacements: 33 | 34 | [_replacements setObject:@"main" forKey:@"com.apple.main-thread"]; 35 | } 36 | return self; 37 | } 38 | 39 | 40 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 41 | #pragma mark Configuration 42 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 43 | 44 | @synthesize minQueueLength = _minQueueLength; 45 | @synthesize maxQueueLength = _maxQueueLength; 46 | 47 | - (NSString *)replacementStringForQueueLabel:(NSString *)longLabel 48 | { 49 | NSString *result = nil; 50 | 51 | OSSpinLockLock(&lock); 52 | { 53 | result = [_replacements objectForKey:longLabel]; 54 | } 55 | OSSpinLockUnlock(&lock); 56 | 57 | return result; 58 | } 59 | 60 | - (void)setReplacementString:(NSString *)shortLabel forQueueLabel:(NSString *)longLabel 61 | { 62 | OSSpinLockLock(&lock); 63 | { 64 | if (shortLabel) 65 | [_replacements setObject:shortLabel forKey:longLabel]; 66 | else 67 | [_replacements removeObjectForKey:longLabel]; 68 | } 69 | OSSpinLockUnlock(&lock); 70 | } 71 | 72 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 73 | #pragma mark DDLogFormatter 74 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 75 | 76 | - (NSString *)queueThreadLabelForLogMessage:(DDLogMessage *)logMessage 77 | { 78 | // As per the DDLogFormatter contract, this method is always invoked on the same thread/dispatch_queue 79 | 80 | NSUInteger minQueueLength = self.minQueueLength; 81 | NSUInteger maxQueueLength = self.maxQueueLength; 82 | 83 | // Get the name of the queue, thread, or machID (whichever we are to use). 84 | 85 | NSString *queueThreadLabel = nil; 86 | 87 | BOOL useQueueLabel = YES; 88 | BOOL useThreadName = NO; 89 | 90 | if (logMessage->queueLabel) 91 | { 92 | // If you manually create a thread, it's dispatch_queue will have one of the thread names below. 93 | // Since all such threads have the same name, we'd prefer to use the threadName or the machThreadID. 94 | 95 | char *names[] = { "com.apple.root.low-priority", 96 | "com.apple.root.default-priority", 97 | "com.apple.root.high-priority", 98 | "com.apple.root.low-overcommit-priority", 99 | "com.apple.root.default-overcommit-priority", 100 | "com.apple.root.high-overcommit-priority" }; 101 | 102 | int length = sizeof(names) / sizeof(char *); 103 | 104 | int i; 105 | for (i = 0; i < length; i++) 106 | { 107 | if (strcmp(logMessage->queueLabel, names[i]) == 0) 108 | { 109 | useQueueLabel = NO; 110 | useThreadName = [logMessage->threadName length] > 0; 111 | break; 112 | } 113 | } 114 | } 115 | else 116 | { 117 | useQueueLabel = NO; 118 | useThreadName = [logMessage->threadName length] > 0; 119 | } 120 | 121 | if (useQueueLabel || useThreadName) 122 | { 123 | NSString *fullLabel; 124 | NSString *abrvLabel; 125 | 126 | if (useQueueLabel) 127 | fullLabel = [NSString stringWithUTF8String:logMessage->queueLabel]; 128 | else 129 | fullLabel = logMessage->threadName; 130 | 131 | OSSpinLockLock(&lock); 132 | { 133 | abrvLabel = [_replacements objectForKey:fullLabel]; 134 | } 135 | OSSpinLockUnlock(&lock); 136 | 137 | if (abrvLabel) 138 | queueThreadLabel = abrvLabel; 139 | else 140 | queueThreadLabel = fullLabel; 141 | } 142 | else 143 | { 144 | queueThreadLabel = [NSString stringWithFormat:@"%x", logMessage->machThreadID]; 145 | } 146 | 147 | // Now use the thread label in the output 148 | 149 | NSUInteger labelLength = [queueThreadLabel length]; 150 | 151 | // labelLength > maxQueueLength : truncate 152 | // labelLength < minQueueLength : padding 153 | // : exact 154 | 155 | if ((maxQueueLength > 0) && (labelLength > maxQueueLength)) 156 | { 157 | // Truncate 158 | 159 | return [queueThreadLabel substringToIndex:maxQueueLength]; 160 | } 161 | else if (labelLength < minQueueLength) 162 | { 163 | // Padding 164 | 165 | NSUInteger numSpaces = minQueueLength - labelLength; 166 | 167 | char spaces[numSpaces + 1]; 168 | memset(spaces, ' ', numSpaces); 169 | spaces[numSpaces] = '\0'; 170 | 171 | return [NSString stringWithFormat:@"%@%s", queueThreadLabel, spaces]; 172 | } 173 | else 174 | { 175 | // Exact 176 | 177 | return queueThreadLabel; 178 | } 179 | } 180 | 181 | - (NSString *)formatLogMessage:(DDLogMessage *)logMessage 182 | { 183 | NSString *timestamp = [dateFormatter stringFromDate:(logMessage->timestamp)]; 184 | NSString *queueThreadLabel = [self queueThreadLabelForLogMessage:logMessage]; 185 | 186 | return [NSString stringWithFormat:@"%@ [%@] %@", timestamp, queueThreadLabel, logMessage->logMsg]; 187 | } 188 | 189 | @end 190 | -------------------------------------------------------------------------------- /CocoaHTTPServer/Vendor/CocoaLumberjack/Extensions/README.txt: -------------------------------------------------------------------------------- 1 | This folder contains some sample formatters that may be helpful. 2 | 3 | Feel free to change them, extend them, or use them as the basis for your own custom formatter(s). 4 | 5 | More information about creating your own custom formatters can be found on the wiki: 6 | https://github.com/robbiehanson/CocoaLumberjack/wiki/CustomFormatters 7 | 8 | -------------------------------------------------------------------------------- /HTTPServer/HTTPServer-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.apple.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /HTTPServer/HTTPServer-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'HTTPServer' target in the 'HTTPServer' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /HTTPServer/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /OpenSourceLicenses/CocoaHTTPServer.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2011, Deusty, LLC 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, 7 | with or without modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Neither the name of Deusty nor the names of its 14 | contributors may be used to endorse or promote products 15 | derived from this software without specific prior 16 | written permission of Deusty, LLC. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /OpenSourceLicenses/ProtocolBuffers.txt: -------------------------------------------------------------------------------- 1 | Copyright 2010 Booyah Inc. 2 | Copyright 2008 Cyrus Najmabadi 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | -------------------------------------------------------------------------------- /OpenSourceLicenses/RoutingHTTPServer.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 Matt Stevens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /OpenSourceVersions/HTTPServer.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | OpenSourceImportDate 7 | 2012-08-20 8 | OpenSourceLicense 9 | BSD 10 | OpenSourceLicenseFile 11 | CocoaHTTPServer.txt 12 | OpenSourceModifications 13 | 14 | sendfile support 15 | 16 | OpenSourceProject 17 | CocoaHTTPServer 18 | OpenSourceVersion 19 | 2.3 20 | OpenSourceWebsiteURL 21 | https://github.com/robbiehanson/CocoaHTTPServer 22 | 23 | 24 | OpenSourceImportDate 25 | 2012-08-29 26 | OpenSourceLicense 27 | MIT 28 | OpenSourceLicenseFile 29 | RoutingHTTPServer.txt 30 | OpenSourceModifications 31 | 32 | OpenSourceProject 33 | RoutingHTTPServer 34 | OpenSourceVersion 35 | 1.0.0 36 | OpenSourceWebsiteURL 37 | https://github.com/mattstevens/RoutingHTTPServer 38 | 39 | 40 | OpenSourceImportDate 41 | 2012-08-30 42 | OpenSourceLicense 43 | Apache 44 | OpenSourceLicenseFile 45 | ProtocolBuffers.txt 46 | OpenSourceModifications 47 | 48 | OpenSourceProject 49 | protobuf-objc 50 | OpenSourceVersion 51 | 696b7b61cdd4e8d77c55ace98b3119194fa04b7f 52 | OpenSourceWebsiteURL 53 | https://github.com/booyah/protobuf-objc 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /ProtocolBuffers/AbstractMessage.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Message.h" 19 | 20 | /** 21 | * A partial implementation of the {@link Message} interface which implements 22 | * as many methods of that interface as possible in terms of other methods. 23 | * 24 | * @author Cyrus Najmabadi 25 | */ 26 | @interface PBAbstractMessage : NSObject { 27 | @private 28 | } 29 | 30 | /** 31 | * Writes a string description of the message into the given mutable string 32 | * respecting a given indent. 33 | */ 34 | - (void)writeDescriptionTo:(NSMutableString*) output 35 | withIndent:(NSString*) indent; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /ProtocolBuffers/AbstractMessage.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "AbstractMessage.h" 19 | 20 | #import "CodedOutputStream.h" 21 | 22 | @implementation PBAbstractMessage 23 | 24 | - (id) init { 25 | if ((self = [super init])) { 26 | } 27 | 28 | return self; 29 | } 30 | 31 | 32 | - (NSData*) data { 33 | NSMutableData* data = [NSMutableData dataWithLength:self.serializedSize]; 34 | PBCodedOutputStream* stream = [PBCodedOutputStream streamWithData:data]; 35 | [self writeToCodedOutputStream:stream]; 36 | return data; 37 | } 38 | 39 | 40 | - (BOOL) isInitialized { 41 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 42 | } 43 | 44 | 45 | - (int32_t) serializedSize { 46 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 47 | } 48 | 49 | 50 | - (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { 51 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 52 | } 53 | 54 | 55 | - (void) writeToOutputStream:(NSOutputStream*) output { 56 | PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output]; 57 | [self writeToCodedOutputStream:codedOutput]; 58 | [codedOutput flush]; 59 | } 60 | 61 | 62 | - (id) defaultInstance { 63 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 64 | } 65 | 66 | 67 | - (PBUnknownFieldSet*) unknownFields { 68 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 69 | } 70 | 71 | 72 | - (id) builder { 73 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 74 | } 75 | 76 | 77 | - (id) toBuilder { 78 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 79 | } 80 | 81 | 82 | - (void) writeDescriptionTo:(NSMutableString*) output 83 | withIndent:(NSString*) indent { 84 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 85 | } 86 | 87 | 88 | - (NSString*) description { 89 | NSMutableString* output = [NSMutableString string]; 90 | [self writeDescriptionTo:output withIndent:@""]; 91 | return output; 92 | } 93 | 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /ProtocolBuffers/AbstractMessage_Builder.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Message_Builder.h" 19 | 20 | /** 21 | * A partial implementation of the {@link Message.Builder} interface which 22 | * implements as many methods of that interface as possible in terms of 23 | * other methods. 24 | */ 25 | @interface PBAbstractMessage_Builder : NSObject { 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /ProtocolBuffers/AbstractMessage_Builder.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "AbstractMessage_Builder.h" 19 | 20 | #import "CodedInputStream.h" 21 | #import "ExtensionRegistry.h" 22 | #import "Message_Builder.h" 23 | #import "UnknownFieldSet.h" 24 | #import "UnknownFieldSet_Builder.h" 25 | 26 | 27 | @implementation PBAbstractMessage_Builder 28 | 29 | - (id) clone { 30 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 31 | } 32 | 33 | 34 | - (id) clear { 35 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 36 | } 37 | 38 | 39 | - (id) mergeFromCodedInputStream:(PBCodedInputStream*) input { 40 | return [self mergeFromCodedInputStream:input extensionRegistry:[PBExtensionRegistry emptyRegistry]]; 41 | } 42 | 43 | 44 | - (id) mergeFromCodedInputStream:(PBCodedInputStream*) input 45 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry { 46 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 47 | } 48 | 49 | 50 | - (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields { 51 | PBUnknownFieldSet* merged = 52 | [[[PBUnknownFieldSet builderWithUnknownFields:self.unknownFields] 53 | mergeUnknownFields:unknownFields] build]; 54 | 55 | [self setUnknownFields:merged]; 56 | return self; 57 | } 58 | 59 | 60 | - (id) mergeFromData:(NSData*) data { 61 | PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; 62 | [self mergeFromCodedInputStream:input]; 63 | [input checkLastTagWas:0]; 64 | return self; 65 | } 66 | 67 | 68 | - (id) mergeFromData:(NSData*) data 69 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry { 70 | PBCodedInputStream* input = [PBCodedInputStream streamWithData:data]; 71 | [self mergeFromCodedInputStream:input extensionRegistry:extensionRegistry]; 72 | [input checkLastTagWas:0]; 73 | return self; 74 | } 75 | 76 | 77 | - (id) mergeFromInputStream:(NSInputStream*) input { 78 | PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input]; 79 | [self mergeFromCodedInputStream:codedInput]; 80 | [codedInput checkLastTagWas:0]; 81 | return self; 82 | } 83 | 84 | 85 | - (id) mergeFromInputStream:(NSInputStream*) input 86 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry { 87 | PBCodedInputStream* codedInput = [PBCodedInputStream streamWithInputStream:input]; 88 | [self mergeFromCodedInputStream:codedInput extensionRegistry:extensionRegistry]; 89 | [codedInput checkLastTagWas:0]; 90 | return self; 91 | } 92 | 93 | 94 | - (id) build { 95 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 96 | } 97 | 98 | 99 | - (id) buildPartial { 100 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 101 | } 102 | 103 | 104 | - (BOOL) isInitialized { 105 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 106 | } 107 | 108 | 109 | - (id) defaultInstance { 110 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 111 | } 112 | 113 | 114 | - (PBUnknownFieldSet*) unknownFields { 115 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 116 | } 117 | 118 | 119 | - (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields { 120 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 121 | } 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /ProtocolBuffers/Bootstrap.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "ForwardDeclarations.h" 19 | 20 | #import "CodedInputStream.h" 21 | #import "CodedOutputStream.h" 22 | #import "ExtendableMessage.h" 23 | #import "ExtendableMessage_Builder.h" 24 | #import "ExtensionRegistry.h" 25 | #import "GeneratedMessage.h" 26 | #import "GeneratedMessage_Builder.h" 27 | #import "Message_Builder.h" 28 | #import "UnknownFieldSet.h" 29 | #import "UnknownFieldSet_Builder.h" 30 | #import "Utilities.h" 31 | -------------------------------------------------------------------------------- /ProtocolBuffers/CodedInputStream.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | @class PBExtensionRegistry; 19 | @class PBUnknownFieldSet_Builder; 20 | @protocol PBMessage_Builder; 21 | 22 | /** 23 | * Reads and decodes protocol message fields. 24 | * 25 | * This class contains two kinds of methods: methods that read specific 26 | * protocol message constructs and field types (e.g. {@link #readTag()} and 27 | * {@link #readInt32()}) and methods that read low-level values (e.g. 28 | * {@link #readRawVarint32()} and {@link #readRawBytes}). If you are reading 29 | * encoded protocol messages, you should use the former methods, but if you are 30 | * reading some other format of your own design, use the latter. 31 | * 32 | * @author Cyrus Najmabadi 33 | */ 34 | @interface PBCodedInputStream : NSObject { 35 | @private 36 | NSMutableData* buffer; 37 | int32_t bufferSize; 38 | int32_t bufferSizeAfterLimit; 39 | int32_t bufferPos; 40 | NSInputStream* input; 41 | int32_t lastTag; 42 | 43 | /** 44 | * The total number of bytes read before the current buffer. The total 45 | * bytes read up to the current position can be computed as 46 | * {@code totalBytesRetired + bufferPos}. 47 | */ 48 | int32_t totalBytesRetired; 49 | 50 | /** The absolute position of the end of the current message. */ 51 | int32_t currentLimit; 52 | 53 | /** See setRecursionLimit() */ 54 | int32_t recursionDepth; 55 | int32_t recursionLimit; 56 | 57 | /** See setSizeLimit() */ 58 | int32_t sizeLimit; 59 | } 60 | 61 | + (PBCodedInputStream*) streamWithData:(NSData*) data; 62 | + (PBCodedInputStream*) streamWithInputStream:(NSInputStream*) input; 63 | 64 | /** 65 | * Attempt to read a field tag, returning zero if we have reached EOF. 66 | * Protocol message parsers use this to read tags, since a protocol message 67 | * may legally end wherever a tag occurs, and zero is not a valid tag number. 68 | */ 69 | - (int32_t) readTag; 70 | - (BOOL) refillBuffer:(BOOL) mustSucceed; 71 | 72 | - (Float64) readDouble; 73 | - (Float32) readFloat; 74 | - (int64_t) readUInt64; 75 | - (int32_t) readUInt32; 76 | - (int64_t) readInt64; 77 | - (int32_t) readInt32; 78 | - (int64_t) readFixed64; 79 | - (int32_t) readFixed32; 80 | - (int32_t) readEnum; 81 | - (int32_t) readSFixed32; 82 | - (int64_t) readSFixed64; 83 | - (int32_t) readSInt32; 84 | - (int64_t) readSInt64; 85 | 86 | /** 87 | * Read one byte from the input. 88 | * 89 | * @throws InvalidProtocolBuffer The end of the stream or the current 90 | * limit was reached. 91 | */ 92 | - (int8_t) readRawByte; 93 | 94 | /** 95 | * Read a raw Varint from the stream. If larger than 32 bits, discard the 96 | * upper bits. 97 | */ 98 | - (int32_t) readRawVarint32; 99 | - (int64_t) readRawVarint64; 100 | - (int32_t) readRawLittleEndian32; 101 | - (int64_t) readRawLittleEndian64; 102 | 103 | /** 104 | * Read a fixed size of bytes from the input. 105 | * 106 | * @throws InvalidProtocolBuffer The end of the stream or the current 107 | * limit was reached. 108 | */ 109 | - (NSData*) readRawData:(int32_t) size; 110 | 111 | /** 112 | * Reads and discards a single field, given its tag value. 113 | * 114 | * @return {@code false} if the tag is an endgroup tag, in which case 115 | * nothing is skipped. Otherwise, returns {@code true}. 116 | */ 117 | - (BOOL) skipField:(int32_t) tag; 118 | 119 | 120 | /** 121 | * Reads and discards {@code size} bytes. 122 | * 123 | * @throws InvalidProtocolBuffer The end of the stream or the current 124 | * limit was reached. 125 | */ 126 | - (void) skipRawData:(int32_t) size; 127 | 128 | /** 129 | * Reads and discards an entire message. This will read either until EOF 130 | * or until an endgroup tag, whichever comes first. 131 | */ 132 | - (void) skipMessage; 133 | 134 | - (BOOL) isAtEnd; 135 | - (int32_t) pushLimit:(int32_t) byteLimit; 136 | - (void) recomputeBufferSizeAfterLimit; 137 | - (void) popLimit:(int32_t) oldLimit; 138 | - (int32_t) bytesUntilLimit; 139 | 140 | 141 | /** Read an embedded message field value from the stream. */ 142 | - (void) readMessage:(id) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry; 143 | 144 | - (BOOL) readBool; 145 | - (NSString*) readString; 146 | - (NSData*) readData; 147 | 148 | - (void) readGroup:(int32_t) fieldNumber builder:(id) builder extensionRegistry:(PBExtensionRegistry*) extensionRegistry; 149 | 150 | /** 151 | * Reads a {@code group} field value from the stream and merges it into the 152 | * given {@link UnknownFieldSet}. 153 | */ 154 | - (void) readUnknownGroup:(int32_t) fieldNumber builder:(PBUnknownFieldSet_Builder*) builder; 155 | 156 | /** 157 | * Verifies that the last call to readTag() returned the given tag value. 158 | * This is used to verify that a nested group ended with the correct 159 | * end tag. 160 | * 161 | * @throws InvalidProtocolBuffer {@code value} does not match the 162 | * last tag. 163 | */ 164 | - (void) checkLastTagWas:(int32_t) value; 165 | 166 | @end 167 | -------------------------------------------------------------------------------- /ProtocolBuffers/CodedOutputStream.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | /** 19 | * Encodes and writes protocol message fields. 20 | * 21 | *

    This class contains two kinds of methods: methods that write specific 22 | * protocol message constructs and field types (e.g. {@link #writeTag} and 23 | * {@link #writeInt32}) and methods that write low-level values (e.g. 24 | * {@link #writeRawVarint32} and {@link #writeRawBytes}). If you are 25 | * writing encoded protocol messages, you should use the former methods, but if 26 | * you are writing some other format of your own design, use the latter. 27 | * 28 | *

    This class is totally unsynchronized. 29 | * 30 | * @author Cyrus Najmabadi 31 | */ 32 | 33 | @class PBUnknownFieldSet; 34 | @class RingBuffer; 35 | @protocol PBMessage; 36 | 37 | @interface PBCodedOutputStream : NSObject { 38 | NSOutputStream *output; 39 | RingBuffer *buffer; 40 | } 41 | 42 | + (PBCodedOutputStream*) streamWithData:(NSMutableData*) data; 43 | + (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output; 44 | + (PBCodedOutputStream*) streamWithOutputStream:(NSOutputStream*) output bufferSize:(int32_t) bufferSize; 45 | 46 | /** 47 | * Flushes the stream and forces any buffered bytes to be written. This 48 | * does not flush the underlying NSOutputStream. Returns free space in buffer. 49 | */ 50 | - (void) flush; 51 | 52 | /** Write a single byte. */ 53 | - (void) writeRawByte:(uint8_t) value; 54 | 55 | /** Encode and write a tag. */ 56 | - (void) writeTag:(int32_t) fieldNumber format:(int32_t) format; 57 | 58 | /** Write a little-endian 32-bit integer. */ 59 | - (void) writeRawLittleEndian32:(int32_t) value; 60 | /** Write a little-endian 64-bit integer. */ 61 | - (void) writeRawLittleEndian64:(int64_t) value; 62 | 63 | /** 64 | * Encode and write a varint. {@code value} is treated as 65 | * unsigned, so it won't be sign-extended if negative. 66 | */ 67 | - (void) writeRawVarint32:(int32_t) value; 68 | /** Encode and write a varint. */ 69 | - (void) writeRawVarint64:(int64_t) value; 70 | 71 | //- (void) writeRawLittleEndian32:(int32_t) value; 72 | //- (void) writeRawLittleEndian64:(int64_t) value; 73 | 74 | /** Write an array of bytes. */ 75 | - (void) writeRawData:(const NSData*) data; 76 | - (void) writeRawData:(const NSData*) data offset:(int32_t) offset length:(int32_t) length; 77 | 78 | - (void) writeData:(int32_t) fieldNumber value:(const NSData*) value; 79 | 80 | - (void) writeDouble:(int32_t) fieldNumber value:(Float64) value; 81 | - (void) writeFloat:(int32_t) fieldNumber value:(Float32) value; 82 | - (void) writeUInt64:(int32_t) fieldNumber value:(int64_t) value; 83 | - (void) writeInt64:(int32_t) fieldNumber value:(int64_t) value; 84 | - (void) writeInt32:(int32_t) fieldNumber value:(int32_t) value; 85 | - (void) writeFixed64:(int32_t) fieldNumber value:(int64_t) value; 86 | - (void) writeFixed32:(int32_t) fieldNumber value:(int32_t) value; 87 | - (void) writeBool:(int32_t) fieldNumber value:(BOOL) value; 88 | - (void) writeString:(int32_t) fieldNumber value:(const NSString*) value; 89 | - (void) writeGroup:(int32_t) fieldNumber value:(const id) value; 90 | - (void) writeUnknownGroup:(int32_t) fieldNumber value:(const PBUnknownFieldSet*) value; 91 | - (void) writeMessage:(int32_t) fieldNumber value:(const id) value; 92 | - (void) writeUInt32:(int32_t) fieldNumber value:(int32_t) value; 93 | - (void) writeSFixed32:(int32_t) fieldNumber value:(int32_t) value; 94 | - (void) writeSFixed64:(int32_t) fieldNumber value:(int64_t) value; 95 | - (void) writeSInt32:(int32_t) fieldNumber value:(int32_t) value; 96 | - (void) writeSInt64:(int32_t) fieldNumber value:(int64_t) value; 97 | 98 | - (void) writeDoubleNoTag:(Float64) value; 99 | - (void) writeFloatNoTag:(Float32) value; 100 | - (void) writeUInt64NoTag:(int64_t) value; 101 | - (void) writeInt64NoTag:(int64_t) value; 102 | - (void) writeInt32NoTag:(int32_t) value; 103 | - (void) writeFixed64NoTag:(int64_t) value; 104 | - (void) writeFixed32NoTag:(int32_t) value; 105 | - (void) writeBoolNoTag:(BOOL) value; 106 | - (void) writeStringNoTag:(const NSString*) value; 107 | - (void) writeGroupNoTag:(int32_t) fieldNumber value:(const id) value; 108 | - (void) writeUnknownGroupNoTag:(int32_t) fieldNumber value:(const PBUnknownFieldSet*) value; 109 | - (void) writeMessageNoTag:(const id) value; 110 | - (void) writeDataNoTag:(const NSData*) value; 111 | - (void) writeUInt32NoTag:(int32_t) value; 112 | - (void) writeEnumNoTag:(int32_t) value; 113 | - (void) writeSFixed32NoTag:(int32_t) value; 114 | - (void) writeSFixed64NoTag:(int64_t) value; 115 | - (void) writeSInt32NoTag:(int32_t) value; 116 | - (void) writeSInt64NoTag:(int64_t) value; 117 | 118 | 119 | /** 120 | * Write a MessageSet extension field to the stream. For historical reasons, 121 | * the wire format differs from normal fields. 122 | */ 123 | - (void) writeMessageSetExtension:(int32_t) fieldNumber value:(const id) value; 124 | 125 | /** 126 | * Write an unparsed MessageSet extension field to the stream. For 127 | * historical reasons, the wire format differs from normal fields. 128 | */ 129 | - (void) writeRawMessageSetExtension:(int32_t) fieldNumber value:(const NSData*) value; 130 | 131 | /** 132 | * Write an enum field, including tag, to the stream. Caller is responsible 133 | * for converting the enum value to its numeric value. 134 | */ 135 | - (void) writeEnum:(int32_t) fieldNumber value:(int32_t) value; 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /ProtocolBuffers/ConcreteExtensionField.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "ExtensionField.h" 19 | 20 | typedef enum { 21 | PBExtensionTypeBool, 22 | PBExtensionTypeFixed32, 23 | PBExtensionTypeSFixed32, 24 | PBExtensionTypeFloat, 25 | PBExtensionTypeFixed64, 26 | PBExtensionTypeSFixed64, 27 | PBExtensionTypeDouble, 28 | PBExtensionTypeInt32, 29 | PBExtensionTypeInt64, 30 | PBExtensionTypeSInt32, 31 | PBExtensionTypeSInt64, 32 | PBExtensionTypeUInt32, 33 | PBExtensionTypeUInt64, 34 | PBExtensionTypeBytes, 35 | PBExtensionTypeString, 36 | PBExtensionTypeMessage, 37 | PBExtensionTypeGroup, 38 | PBExtensionTypeEnum 39 | } PBExtensionType; 40 | 41 | @interface PBConcreteExtensionField : NSObject { 42 | @private 43 | PBExtensionType type; 44 | 45 | Class extendedClass; 46 | int32_t fieldNumber; 47 | id defaultValue; 48 | 49 | Class messageOrGroupClass; 50 | 51 | BOOL isRepeated; 52 | BOOL isPacked; 53 | BOOL isMessageSetWireFormat; 54 | } 55 | 56 | + (PBConcreteExtensionField*) extensionWithType:(PBExtensionType) type 57 | extendedClass:(Class) extendedClass 58 | fieldNumber:(int32_t) fieldNumber 59 | defaultValue:(id) defaultValue 60 | messageOrGroupClass:(Class) messageOrGroupClass 61 | isRepeated:(BOOL) isRepeated 62 | isPacked:(BOOL) isPacked 63 | isMessageSetWireFormat:(BOOL) isMessageSetWireFormat; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtendableMessage.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "GeneratedMessage.h" 19 | 20 | #import "ExtensionField.h" 21 | 22 | /** 23 | * Generated message classes for message types that contain extension ranges 24 | * subclass this. 25 | * 26 | *

    This class implements type-safe accessors for extensions. They 27 | * implement all the same operations that you can do with normal fields -- 28 | * e.g. "has", "get", and "getCount" -- but for extensions. The extensions 29 | * are identified using instances of the class {@link GeneratedExtension}; 30 | * the protocol compiler generates a static instance of this class for every 31 | * extension in its input. Through the magic of generics, all is made 32 | * type-safe. 33 | * 34 | *

    For example, imagine you have the {@code .proto} file: 35 | * 36 | *

    37 |  * option java_class = "MyProto";
    38 |  *
    39 |  * message Foo {
    40 |  *   extensions 1000 to max;
    41 |  * }
    42 |  *
    43 |  * extend Foo {
    44 |  *   optional int32 bar;
    45 |  * }
    46 |  * 
    47 | * 48 | *

    Then you might write code like: 49 | * 50 | *

    51 |  * MyProto.Foo foo = getFoo();
    52 |  * int i = foo.getExtension(MyProto.bar);
    53 |  * 
    54 | * 55 | *

    See also {@link ExtendableBuilder}. 56 | */ 57 | @interface PBExtendableMessage : PBGeneratedMessage { 58 | @private 59 | NSMutableDictionary* extensionMap; 60 | NSMutableDictionary* extensionRegistry; 61 | } 62 | 63 | @property (retain) NSMutableDictionary* extensionMap; 64 | @property (retain) NSMutableDictionary* extensionRegistry; 65 | 66 | - (BOOL) hasExtension:(id) extension; 67 | - (id) getExtension:(id) extension; 68 | 69 | //@protected 70 | - (BOOL) extensionsAreInitialized; 71 | - (int32_t) extensionsSerializedSize; 72 | - (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output 73 | from:(int32_t) startInclusive 74 | to:(int32_t) endExclusive; 75 | - (void) writeExtensionDescriptionToMutableString:(NSMutableString*) output 76 | from:(int32_t) startInclusive 77 | to:(int32_t) endExclusive 78 | withIndent:(NSString*) indent; 79 | - (BOOL) isEqualExtensionsInOther:(PBExtendableMessage*)otherMessage 80 | from:(int32_t) startInclusive 81 | to:(int32_t) endExclusive; 82 | - (NSUInteger) hashExtensionsFrom:(int32_t) startInclusive 83 | to:(int32_t) endExclusive; 84 | 85 | 86 | 87 | /* @internal */ 88 | - (void) ensureExtensionIsRegistered:(id) extension; 89 | 90 | @end 91 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtendableMessage.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "ExtendableMessage.h" 19 | 20 | #import "ExtensionField.h" 21 | 22 | @implementation PBExtendableMessage 23 | 24 | @synthesize extensionMap; 25 | @synthesize extensionRegistry; 26 | 27 | - (void) dealloc { 28 | self.extensionMap = nil; 29 | self.extensionRegistry = nil; 30 | [super dealloc]; 31 | } 32 | 33 | 34 | - (BOOL) isInitialized:(id) object { 35 | if ([object isKindOfClass:[NSArray class]]) { 36 | for (id child in object) { 37 | if (![self isInitialized:child]) { 38 | return NO; 39 | } 40 | } 41 | } else if ([object conformsToProtocol:@protocol(PBMessage)]) { 42 | return [object isInitialized]; 43 | } 44 | 45 | return YES; 46 | } 47 | 48 | 49 | - (BOOL) extensionsAreInitialized { 50 | return [self isInitialized:extensionMap.allValues]; 51 | } 52 | 53 | 54 | - (id) getExtension:(id) extension { 55 | [self ensureExtensionIsRegistered:extension]; 56 | id value = [extensionMap objectForKey:[NSNumber numberWithInt:[extension fieldNumber]]]; 57 | if (value != nil) { 58 | return value; 59 | } 60 | 61 | return [extension defaultValue]; 62 | } 63 | 64 | 65 | - (void) ensureExtensionIsRegistered:(id) extension { 66 | if ([extension extendedClass] != [self class]) { 67 | @throw [NSException exceptionWithName:@"IllegalArgument" reason:@"Trying to use an extension for another type" userInfo:nil]; 68 | } 69 | 70 | if (extensionRegistry == nil) { 71 | self.extensionRegistry = [NSMutableDictionary dictionary]; 72 | } 73 | [extensionRegistry setObject:extension 74 | forKey:[NSNumber numberWithInt:[extension fieldNumber]]]; 75 | } 76 | 77 | 78 | - (BOOL) hasExtension:(id) extension { 79 | return nil != [extensionMap objectForKey:[NSNumber numberWithInt:[extension fieldNumber]]]; 80 | } 81 | 82 | 83 | - (void) writeExtensionsToCodedOutputStream:(PBCodedOutputStream*) output 84 | from:(int32_t) startInclusive 85 | to:(int32_t) endExclusive { 86 | // man, i really wish Cocoa had a Sorted/TreeMap 87 | NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; 88 | for (NSNumber* number in sortedKeys) { 89 | int32_t fieldNumber = [number intValue]; 90 | if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { 91 | id extension = [extensionRegistry objectForKey:number]; 92 | id value = [extensionMap objectForKey:number]; 93 | [extension writeValue:value includingTagToCodedOutputStream:output]; 94 | } 95 | } 96 | } 97 | 98 | 99 | - (void) writeExtensionDescriptionToMutableString:(NSMutableString*) output 100 | from:(int32_t) startInclusive 101 | to:(int32_t) endExclusive 102 | withIndent:(NSString*) indent { 103 | NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; 104 | for (NSNumber* number in sortedKeys) { 105 | int32_t fieldNumber = [number intValue]; 106 | if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { 107 | id extension = [extensionRegistry objectForKey:number]; 108 | id value = [extensionMap objectForKey:number]; 109 | [extension writeDescriptionOf:value to:output withIndent:indent]; 110 | } 111 | } 112 | } 113 | 114 | 115 | - (BOOL) isEqualExtensionsInOther:(PBExtendableMessage*)otherMessage 116 | from:(int32_t) startInclusive 117 | to:(int32_t) endExclusive { 118 | NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; 119 | for (NSNumber* number in sortedKeys) { 120 | int32_t fieldNumber = [number intValue]; 121 | if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { 122 | id value = [extensionMap objectForKey:number]; 123 | id otherValue = [otherMessage.extensionMap objectForKey:number]; 124 | if (![value isEqual:otherValue]) { 125 | return NO; 126 | } 127 | } 128 | } 129 | return YES; 130 | } 131 | 132 | 133 | - (NSUInteger) hashExtensionsFrom:(int32_t) startInclusive 134 | to:(int32_t) endExclusive { 135 | NSUInteger hashCode = 0; 136 | NSArray* sortedKeys = [extensionMap.allKeys sortedArrayUsingSelector:@selector(compare:)]; 137 | for (NSNumber* number in sortedKeys) { 138 | int32_t fieldNumber = [number intValue]; 139 | if (fieldNumber >= startInclusive && fieldNumber < endExclusive) { 140 | id value = [extensionMap objectForKey:number]; 141 | hashCode = hashCode * 31 + [value hash]; 142 | } 143 | } 144 | return hashCode; 145 | } 146 | 147 | 148 | - (int32_t) extensionsSerializedSize { 149 | int32_t size = 0; 150 | for (NSNumber* number in extensionMap) { 151 | id extension = [extensionRegistry objectForKey:number]; 152 | id value = [extensionMap objectForKey:number]; 153 | size += [extension computeSerializedSizeIncludingTag:value]; 154 | } 155 | 156 | return size; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtendableMessage_Builder.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "GeneratedMessage_Builder.h" 19 | 20 | #import "ExtensionField.h" 21 | 22 | @class PBExtendableMessage; 23 | 24 | /** 25 | * Generated message builders for message types that contain extension ranges 26 | * subclass this. 27 | * 28 | *

    This class implements type-safe accessors for extensions. They 29 | * implement all the same operations that you can do with normal fields -- 30 | * e.g. "get", "set", and "add" -- but for extensions. The extensions are 31 | * identified using instances of the class {@link GeneratedExtension}; the 32 | * protocol compiler generates a static instance of this class for every 33 | * extension in its input. Through the magic of generics, all is made 34 | * type-safe. 35 | * 36 | *

    For example, imagine you have the {@code .proto} file: 37 | * 38 | *

    39 |  * option java_class = "MyProto";
    40 |  *
    41 |  * message Foo {
    42 |  *   extensions 1000 to max;
    43 |  * }
    44 |  *
    45 |  * extend Foo {
    46 |  *   optional int32 bar;
    47 |  * }
    48 |  * 
    49 | * 50 | *

    Then you might write code like: 51 | * 52 | *

    53 |  * MyProto.Foo foo =
    54 |  *   MyProto.Foo.newBuilder()
    55 |  *     .setExtension(MyProto.bar, 123)
    56 |  *     .build();
    57 |  * 
    58 | * 59 | *

    See also {@link ExtendableMessage}. 60 | */ 61 | @interface PBExtendableMessage_Builder : PBGeneratedMessage_Builder { 62 | } 63 | 64 | - (id) getExtension:(id) extension; 65 | - (BOOL) hasExtension:(id) extension; 66 | - (PBExtendableMessage_Builder*) setExtension:(id) extension 67 | value:(id) value; 68 | - (PBExtendableMessage_Builder*) addExtension:(id) extension 69 | value:(id) value; 70 | - (PBExtendableMessage_Builder*) setExtension:(id) extension 71 | index:(int32_t) index 72 | value:(id) value; 73 | - (PBExtendableMessage_Builder*) clearExtension:(id) extension; 74 | 75 | /* @protected */ 76 | - (void) mergeExtensionFields:(PBExtendableMessage*) other; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtensionField.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "WireFormat.h" 19 | 20 | @class PBCodedInputStream; 21 | @class PBCodedOutputStream; 22 | @class PBExtendableMessage_Builder; 23 | @class PBExtensionRegistry; 24 | @class PBUnknownFieldSet_Builder; 25 | 26 | @protocol PBExtensionField 27 | - (int32_t) fieldNumber; 28 | - (PBWireFormat) wireType; 29 | - (BOOL) isRepeated; 30 | - (Class) extendedClass; 31 | - (id) defaultValue; 32 | 33 | - (void) mergeFromCodedInputStream:(PBCodedInputStream*) input 34 | unknownFields:(PBUnknownFieldSet_Builder*) unknownFields 35 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry 36 | builder:(PBExtendableMessage_Builder*) builder 37 | tag:(int32_t) tag; 38 | - (void) writeValue:(id) value includingTagToCodedOutputStream:(PBCodedOutputStream*) output; 39 | - (int32_t) computeSerializedSizeIncludingTag:(id) value; 40 | - (void) writeDescriptionOf:(id) value 41 | to:(NSMutableString*) output 42 | withIndent:(NSString*) indent; 43 | @end 44 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtensionRegistry.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | /** 19 | * A table of known extensions, searchable by name or field number. When 20 | * parsing a protocol message that might have extensions, you must provide 21 | * an {@code ExtensionRegistry} in which you have registered any extensions 22 | * that you want to be able to parse. Otherwise, those extensions will just 23 | * be treated like unknown fields. 24 | * 25 | *

    For example, if you had the {@code .proto} file: 26 | * 27 | *

    28 |  * option java_class = "MyProto";
    29 |  *
    30 |  * message Foo {
    31 |  *   extensions 1000 to max;
    32 |  * }
    33 |  *
    34 |  * extend Foo {
    35 |  *   optional int32 bar;
    36 |  * }
    37 |  * 
    38 | * 39 | * Then you might write code like: 40 | * 41 | *
    42 |  * ExtensionRegistry registry = ExtensionRegistry.newInstance();
    43 |  * registry.add(MyProto.bar);
    44 |  * MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
    45 |  * 
    46 | * 47 | *

    Background: 48 | * 49 | *

    You might wonder why this is necessary. Two alternatives might come to 50 | * mind. First, you might imagine a system where generated extensions are 51 | * automatically registered when their containing classes are loaded. This 52 | * is a popular technique, but is bad design; among other things, it creates a 53 | * situation where behavior can change depending on what classes happen to be 54 | * loaded. It also introduces a security vulnerability, because an 55 | * unprivileged class could cause its code to be called unexpectedly from a 56 | * privileged class by registering itself as an extension of the right type. 57 | * 58 | *

    Another option you might consider is lazy parsing: do not parse an 59 | * extension until it is first requested, at which point the caller must 60 | * provide a type to use. This introduces a different set of problems. First, 61 | * it would require a mutex lock any time an extension was accessed, which 62 | * would be slow. Second, corrupt data would not be detected until first 63 | * access, at which point it would be much harder to deal with it. Third, it 64 | * could violate the expectation that message objects are immutable, since the 65 | * type provided could be any arbitrary message class. An unpriviledged user 66 | * could take advantage of this to inject a mutable object into a message 67 | * belonging to priviledged code and create mischief. 68 | * 69 | * @author Cyrus Najmabadi 70 | */ 71 | 72 | #import "ExtensionField.h" 73 | 74 | @interface PBExtensionRegistry : NSObject { 75 | @protected 76 | NSDictionary* classMap; 77 | } 78 | 79 | + (PBExtensionRegistry*) emptyRegistry; 80 | - (id) getExtension:(Class) clazz fieldNumber:(NSInteger) fieldNumber; 81 | 82 | /* @protected */ 83 | - (id) initWithClassMap:(NSDictionary*) classMap; 84 | - (id) keyForClass:(Class) clazz; 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /ProtocolBuffers/ExtensionRegistry.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "ExtensionRegistry.h" 19 | 20 | @interface PBExtensionRegistry() 21 | @property (retain) NSDictionary* classMap; 22 | @end 23 | 24 | @implementation PBExtensionRegistry 25 | 26 | @synthesize classMap; 27 | 28 | - (void) dealloc { 29 | self.classMap = nil; 30 | [super dealloc]; 31 | } 32 | 33 | static PBExtensionRegistry* emptyRegistry = nil; 34 | 35 | + (void) initialize { 36 | if (self == [PBExtensionRegistry class]) { 37 | emptyRegistry = [[PBExtensionRegistry alloc] initWithClassMap:[NSDictionary dictionary]]; 38 | } 39 | } 40 | 41 | 42 | - (id) initWithClassMap:(NSDictionary*) map_{ 43 | if ((self = [super init])) { 44 | self.classMap = map_; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | 51 | - (id) keyForClass:(Class) clazz { 52 | return NSStringFromClass(clazz); 53 | } 54 | 55 | 56 | + (PBExtensionRegistry*) emptyRegistry { 57 | return emptyRegistry; 58 | } 59 | 60 | 61 | - (id) getExtension:(Class) clazz fieldNumber:(NSInteger) fieldNumber { 62 | NSDictionary* extensionMap = [classMap objectForKey:[self keyForClass:clazz]]; 63 | return [extensionMap objectForKey:[NSNumber numberWithInteger:fieldNumber]]; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /ProtocolBuffers/Field.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import 19 | 20 | @class PBArray; 21 | @class PBAppendableArray; 22 | @class PBCodedOutputStream; 23 | 24 | @interface PBField : NSObject 25 | { 26 | @protected 27 | PBAppendableArray * _varintArray; 28 | PBAppendableArray * _fixed32Array; 29 | PBAppendableArray * _fixed64Array; 30 | PBAppendableArray * _lengthDelimitedArray; 31 | PBAppendableArray * _groupArray; 32 | } 33 | 34 | @property (nonatomic,retain,readonly) PBArray * varintArray; 35 | @property (nonatomic,retain,readonly) PBArray * fixed32Array; 36 | @property (nonatomic,retain,readonly) PBArray * fixed64Array; 37 | @property (nonatomic,retain,readonly) PBArray * lengthDelimitedArray; 38 | @property (nonatomic,retain,readonly) PBArray * groupArray; 39 | 40 | + (PBField *)defaultInstance; 41 | 42 | - (int32_t)getSerializedSize:(int32_t)fieldNumber; 43 | - (int32_t)getSerializedSizeAsMessageSetExtension:(int32_t)fieldNumber; 44 | 45 | - (void)writeTo:(int32_t) fieldNumber output:(PBCodedOutputStream *)output; 46 | - (void)writeAsMessageSetExtensionTo:(int32_t)fieldNumber output:(PBCodedOutputStream *)output; 47 | - (void)writeDescriptionFor:(int32_t) fieldNumber 48 | to:(NSMutableString*) output 49 | withIndent:(NSString*) indent; 50 | @end 51 | -------------------------------------------------------------------------------- /ProtocolBuffers/Field.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Field.h" 19 | 20 | #import "CodedOutputStream.h" 21 | #import "PBArray.h" 22 | #import "UnknownFieldSet.h" 23 | #import "Utilities.h" 24 | 25 | @implementation PBField 26 | 27 | @synthesize varintArray = _varintArray; 28 | @synthesize fixed32Array = _fixed32Array; 29 | @synthesize fixed64Array = _fixed64Array; 30 | @synthesize lengthDelimitedArray = _lengthDelimitedArray; 31 | @synthesize groupArray = _groupArray; 32 | 33 | static PBField *sDefaultInstance = nil; 34 | 35 | + (void)initialize { 36 | if (self == [PBField class]) { 37 | sDefaultInstance = [[PBField alloc] init]; 38 | } 39 | } 40 | 41 | - (void)dealloc { 42 | [_varintArray release]; 43 | [_fixed32Array release]; 44 | [_fixed64Array release]; 45 | [_lengthDelimitedArray release]; 46 | [_groupArray release]; 47 | [super dealloc]; 48 | } 49 | 50 | + (PBField *)defaultInstance { 51 | return sDefaultInstance; 52 | } 53 | 54 | - (int32_t)getSerializedSize:(int32_t)fieldNumber { 55 | int32_t result = 0; 56 | 57 | const int64_t *varintValues = (const int64_t *)_varintArray.data; 58 | if (varintValues) { 59 | const NSUInteger count = _varintArray.count; 60 | for (NSUInteger i = 0; i < count; ++i) { 61 | result += computeInt64Size(fieldNumber, varintValues[i]); 62 | } 63 | } 64 | 65 | const int32_t *fixed32Values = (const int32_t *)_fixed32Array.data; 66 | if (fixed32Values) { 67 | const NSUInteger count = _fixed32Array.count; 68 | for (NSUInteger i = 0; i < count; ++i) { 69 | result += computeFixed32Size(fieldNumber, fixed32Values[i]); 70 | } 71 | } 72 | 73 | const int64_t *fixed64Values = (const int64_t *)_fixed64Array.data; 74 | if (fixed64Values) { 75 | const NSUInteger count = _fixed64Array.count; 76 | for (NSUInteger i = 0; i < count; ++i) { 77 | result += computeFixed64Size(fieldNumber, fixed64Values[i]); 78 | } 79 | } 80 | 81 | for (NSData *value in _lengthDelimitedArray) { 82 | result += computeDataSize(fieldNumber, value); 83 | } 84 | 85 | for (PBUnknownFieldSet *value in _groupArray) { 86 | result += computeUnknownGroupSize(fieldNumber, value); 87 | } 88 | 89 | return result; 90 | } 91 | 92 | - (int32_t)getSerializedSizeAsMessageSetExtension:(int32_t)fieldNumber { 93 | int32_t result = 0; 94 | 95 | for (NSData *value in _lengthDelimitedArray) { 96 | result += computeRawMessageSetExtensionSize(fieldNumber, value); 97 | } 98 | 99 | return result; 100 | } 101 | 102 | - (void)writeTo:(int32_t)fieldNumber output:(PBCodedOutputStream *) output { 103 | const int64_t *varintValues = (const int64_t *)_varintArray.data; 104 | if (varintValues) { 105 | const NSUInteger count = _varintArray.count; 106 | for (NSUInteger i = 0; i < count; ++i) { 107 | [output writeInt64:fieldNumber value:varintValues[i]]; 108 | } 109 | } 110 | 111 | const int32_t *fixed32Values = (const int32_t *)_fixed32Array.data; 112 | if (fixed32Values) { 113 | const NSUInteger count = _fixed32Array.count; 114 | for (NSUInteger i = 0; i < count; ++i) { 115 | [output writeFixed32:fieldNumber value:fixed32Values[i]]; 116 | } 117 | } 118 | 119 | const int64_t *fixed64Values = (const int64_t *)_fixed64Array.data; 120 | if (fixed64Values) { 121 | const NSUInteger count = _fixed64Array.count; 122 | for (NSUInteger i = 0; i < count; ++i) { 123 | [output writeFixed64:fieldNumber value:fixed64Values[i]]; 124 | } 125 | } 126 | 127 | for (NSData *value in _lengthDelimitedArray) { 128 | [output writeData:fieldNumber value:value]; 129 | } 130 | 131 | for (PBUnknownFieldSet *value in _groupArray) { 132 | [output writeUnknownGroup:fieldNumber value:value]; 133 | } 134 | } 135 | 136 | - (void)writeDescriptionFor:(int32_t) fieldNumber 137 | to:(NSMutableString*) output 138 | withIndent:(NSString*) indent { 139 | for (NSNumber* value in self.varintArray) { 140 | [output appendFormat:@"%@%d: %qi\n", indent, fieldNumber, value.longLongValue]; 141 | } 142 | for (NSNumber* value in self.fixed32Array) { 143 | [output appendFormat:@"%@%d: %d\n", indent, fieldNumber, value.intValue]; 144 | } 145 | for (NSNumber* value in self.fixed64Array) { 146 | [output appendFormat:@"%@%d: %qi\n", indent, fieldNumber, value.longLongValue]; 147 | } 148 | for (NSData* value in self.lengthDelimitedArray) { 149 | [output appendFormat:@"%@%d: %@\n", indent, fieldNumber, value]; 150 | } 151 | for (PBUnknownFieldSet* value in self.groupArray) { 152 | [output appendFormat:@"%@%d: [\n", indent, fieldNumber]; 153 | [value writeDescriptionTo:output withIndent:[NSString stringWithFormat:@"%@ ", indent]]; 154 | [output appendFormat:@"%@]", indent]; 155 | } 156 | } 157 | 158 | - (void)writeAsMessageSetExtensionTo:(int32_t)fieldNumber output:(PBCodedOutputStream *) output { 159 | for (NSData *value in _lengthDelimitedArray) { 160 | [output writeRawMessageSetExtension:fieldNumber value:value]; 161 | } 162 | } 163 | 164 | @end -------------------------------------------------------------------------------- /ProtocolBuffers/ForwardDeclarations.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | @protocol PBMessage; 19 | @protocol PBMessage_Builder; 20 | @protocol PBExtensionField; 21 | 22 | @class PBAbstractMessage; 23 | @class PBCodedInputStream; 24 | @class PBCodedOutputStream; 25 | @class PBConcreteExtensionField; 26 | @class PBExtendableMessage_Builder; 27 | @class PBExtendableMessage; 28 | @class PBExtensionRegistry; 29 | @class PBField; 30 | @class PBGeneratedMessage; 31 | @class PBGeneratedMessage_Builder; 32 | @class PBMutableExtensionRegistry; 33 | @class PBMutableField; 34 | @class PBUnknownFieldSet; 35 | @class PBUnknownFieldSet_Builder; 36 | -------------------------------------------------------------------------------- /ProtocolBuffers/GeneratedMessage.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "AbstractMessage.h" 19 | 20 | /** 21 | * All generated protocol message classes extend this class. This class 22 | * implements most of the Message and Builder interfaces using Java reflection. 23 | * Users can ignore this class and pretend that generated messages implement 24 | * the Message interface directly. 25 | * 26 | * @author Cyrus Najmabadi 27 | */ 28 | @interface PBGeneratedMessage : PBAbstractMessage { 29 | @private 30 | PBUnknownFieldSet* unknownFields; 31 | 32 | @protected 33 | int32_t memoizedSerializedSize; 34 | } 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /ProtocolBuffers/GeneratedMessage.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "GeneratedMessage.h" 19 | 20 | #import "UnknownFieldSet.h" 21 | 22 | @interface PBGeneratedMessage () 23 | @property (retain) PBUnknownFieldSet* unknownFields; 24 | @end 25 | 26 | 27 | @implementation PBGeneratedMessage 28 | 29 | @synthesize unknownFields; 30 | 31 | - (void) dealloc { 32 | self.unknownFields = nil; 33 | [super dealloc]; 34 | } 35 | 36 | 37 | - (id) init { 38 | if ((self = [super init])) { 39 | self.unknownFields = [PBUnknownFieldSet defaultInstance]; 40 | memoizedSerializedSize = -1; 41 | } 42 | 43 | return self; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /ProtocolBuffers/GeneratedMessage_Builder.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "AbstractMessage_Builder.h" 19 | 20 | @class PBUnknownFieldSet_Builder; 21 | 22 | @interface PBGeneratedMessage_Builder : PBAbstractMessage_Builder { 23 | } 24 | 25 | /* @protected */ 26 | - (BOOL) parseUnknownField:(PBCodedInputStream*) input 27 | unknownFields:(PBUnknownFieldSet_Builder*) unknownFields 28 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry 29 | tag:(int32_t) tag; 30 | 31 | - (void) checkInitialized; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /ProtocolBuffers/GeneratedMessage_Builder.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "GeneratedMessage_Builder.h" 19 | 20 | #import "GeneratedMessage.h" 21 | #import "Message.h" 22 | #import "Message_Builder.h" 23 | #import "UnknownFieldSet.h" 24 | #import "UnknownFieldSet_Builder.h" 25 | 26 | 27 | @interface PBGeneratedMessage () 28 | @property (retain) PBUnknownFieldSet* unknownFields; 29 | @end 30 | 31 | 32 | @implementation PBGeneratedMessage_Builder 33 | 34 | /** 35 | * Get the message being built. We don't just pass this to the 36 | * constructor because it becomes null when build() is called. 37 | */ 38 | - (PBGeneratedMessage*) internalGetResult { 39 | @throw [NSException exceptionWithName:@"ImproperSubclassing" reason:@"" userInfo:nil]; 40 | } 41 | 42 | 43 | - (void) checkInitialized { 44 | PBGeneratedMessage* result = self.internalGetResult; 45 | if (result != nil && !result.isInitialized) { 46 | @throw [NSException exceptionWithName:@"UninitializedMessage" reason:@"" userInfo:nil]; 47 | } 48 | } 49 | 50 | 51 | - (PBUnknownFieldSet*) unknownFields { 52 | return self.internalGetResult.unknownFields; 53 | } 54 | 55 | 56 | - (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields { 57 | self.internalGetResult.unknownFields = unknownFields; 58 | return self; 59 | } 60 | 61 | 62 | - (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields { 63 | PBGeneratedMessage* result = self.internalGetResult; 64 | result.unknownFields = 65 | [[[PBUnknownFieldSet builderWithUnknownFields:result.unknownFields] 66 | mergeUnknownFields:unknownFields] build]; 67 | return self; 68 | } 69 | 70 | 71 | - (BOOL) isInitialized { 72 | return self.internalGetResult.isInitialized; 73 | } 74 | 75 | 76 | /** 77 | * Called by subclasses to parse an unknown field. 78 | * @return {@code YES} unless the tag is an end-group tag. 79 | */ 80 | - (BOOL) parseUnknownField:(PBCodedInputStream*) input 81 | unknownFields:(PBUnknownFieldSet_Builder*) unknownFields 82 | extensionRegistry:(PBExtensionRegistry*) extensionRegistry 83 | tag:(int32_t) tag { 84 | return [unknownFields mergeFieldFrom:tag input:input]; 85 | } 86 | 87 | 88 | - (void) checkInitializedParsed { 89 | PBGeneratedMessage* result = self.internalGetResult; 90 | if (result != nil && !result.isInitialized) { 91 | @throw [NSException exceptionWithName:@"InvalidProtocolBuffer" reason:@"" userInfo:nil]; 92 | } 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /ProtocolBuffers/Message.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | @class PBCodedOutputStream; 19 | @class PBUnknownFieldSet; 20 | @protocol PBMessage_Builder; 21 | 22 | /** 23 | * Abstract interface implemented by Protocol Message objects. 24 | * 25 | * @author Cyrus Najmabadi 26 | */ 27 | @protocol PBMessage 28 | /** 29 | * Get an instance of the type with all fields set to their default values. 30 | * This may or may not be a singleton. This differs from the 31 | * {@code getDefaultInstance()} method of generated message classes in that 32 | * this method is an abstract method of the {@code Message} interface 33 | * whereas {@code getDefaultInstance()} is a static method of a specific 34 | * class. They return the same thing. 35 | */ 36 | - (id) defaultInstance; 37 | 38 | /** 39 | * Get the {@code UnknownFieldSet} 40 | */ 41 | - (PBUnknownFieldSet*) unknownFields; 42 | 43 | /** 44 | * Get the number of bytes required to encode this message. The result 45 | * is only computed on the first call and memoized after that. 46 | */ 47 | - (int32_t) serializedSize; 48 | 49 | /** 50 | * Returns true if all required fields in the message and all embedded 51 | * messages are set, false otherwise. 52 | */ 53 | - (BOOL) isInitialized; 54 | 55 | /** 56 | * Serializes the message and writes it to {@code output}. This does not 57 | * flush or close the stream. 58 | */ 59 | - (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; 60 | - (void) writeToOutputStream:(NSOutputStream*) output; 61 | 62 | /** 63 | * Serializes the message to a {@code ByteString} and returns it. This is 64 | * just a trivial wrapper around 65 | * {@link #writeTo(CodedOutputStream)}. 66 | */ 67 | - (NSData*) data; 68 | 69 | /** 70 | * Constructs a new builder for a message of the same type as this message. 71 | */ 72 | - (id) builder; 73 | 74 | /** 75 | * Constructs a builder initialized with the current message. Use this to 76 | * derive a new message from the current one. 77 | */ 78 | - (id) toBuilder; 79 | 80 | /** 81 | * Returns a string description of the message. 82 | */ 83 | - (NSString*) description; 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /ProtocolBuffers/Message_Builder.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Message.h" 19 | 20 | @class PBCodedInputStream; 21 | @class PBExtensionRegistry; 22 | 23 | /** 24 | * Abstract interface implemented by Protocol Message builders. 25 | */ 26 | @protocol PBMessage_Builder 27 | /** Resets all fields to their default values. */ 28 | - (id) clear; 29 | 30 | /** 31 | * Construct the final message. Once this is called, the Builder is no 32 | * longer valid, and calling any other method may throw a 33 | * NullPointerException. If you need to continue working with the builder 34 | * after calling {@code build()}, {@code clone()} it first. 35 | * @throws UninitializedMessageException The message is missing one or more 36 | * required fields (i.e. {@link #isInitialized()} returns false). 37 | * Use {@link #buildPartial()} to bypass this check. 38 | */ 39 | - (id) build; 40 | 41 | /** 42 | * Like {@link #build()}, but does not throw an exception if the message 43 | * is missing required fields. Instead, a partial message is returned. 44 | */ 45 | - (id) buildPartial; 46 | - (id) clone; 47 | 48 | /** 49 | * Returns true if all required fields in the message and all embedded 50 | * messages are set, false otherwise. 51 | */ 52 | - (BOOL) isInitialized; 53 | 54 | /** 55 | * Get the message's type's default instance. 56 | * See {@link Message#getDefaultInstanceForType()}. 57 | */ 58 | - (id) defaultInstance; 59 | 60 | - (PBUnknownFieldSet*) unknownFields; 61 | - (id) setUnknownFields:(PBUnknownFieldSet*) unknownFields; 62 | 63 | /** 64 | * Merge some unknown fields into the {@link UnknownFieldSet} for this 65 | * message. 66 | */ 67 | - (id) mergeUnknownFields:(PBUnknownFieldSet*) unknownFields; 68 | 69 | /** 70 | * Parses a message of this type from the input and merges it with this 71 | * message, as if using {@link Builder#mergeFrom(Message)}. 72 | * 73 | *

    Warning: This does not verify that all required fields are present in 74 | * the input message. If you call {@link #build()} without setting all 75 | * required fields, it will throw an {@link UninitializedMessageException}, 76 | * which is a {@code RuntimeException} and thus might not be caught. There 77 | * are a few good ways to deal with this: 78 | *

      79 | *
    • Call {@link #isInitialized()} to verify that all required fields 80 | * are set before building. 81 | *
    • Parse the message separately using one of the static 82 | * {@code parseFrom} methods, then use {@link #mergeFrom(Message)} 83 | * to merge it with this one. {@code parseFrom} will throw an 84 | * {@link InvalidProtocolBufferException} (an {@code IOException}) 85 | * if some required fields are missing. 86 | *
    • Use {@code buildPartial()} to build, which ignores missing 87 | * required fields. 88 | *
    89 | * 90 | *

    Note: The caller should call 91 | * {@link CodedInputStream#checkLastTagWas(int)} after calling this to 92 | * verify that the last tag seen was the appropriate end-group tag, 93 | * or zero for EOF. 94 | */ 95 | - (id) mergeFromCodedInputStream:(PBCodedInputStream*) input; 96 | 97 | /** 98 | * Like {@link Builder#mergeFrom(CodedInputStream)}, but also 99 | * parses extensions. The extensions that you want to be able to parse 100 | * must be registered in {@code extensionRegistry}. Extensions not in 101 | * the registry will be treated as unknown fields. 102 | */ 103 | - (id) mergeFromCodedInputStream:(PBCodedInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; 104 | 105 | /** 106 | * Parse {@code data} as a message of this type and merge it with the 107 | * message being built. This is just a small wrapper around 108 | * {@link #mergeFrom(CodedInputStream)}. 109 | */ 110 | - (id) mergeFromData:(NSData*) data; 111 | 112 | /** 113 | * Parse {@code data} as a message of this type and merge it with the 114 | * message being built. This is just a small wrapper around 115 | * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}. 116 | */ 117 | - (id) mergeFromData:(NSData*) data extensionRegistry:(PBExtensionRegistry*) extensionRegistry; 118 | 119 | /** 120 | * Parse a message of this type from {@code input} and merge it with the 121 | * message being built. This is just a small wrapper around 122 | * {@link #mergeFrom(CodedInputStream)}. Note that this method always 123 | * reads the entire input (unless it throws an exception). If you 124 | * want it to stop earlier, you will need to wrap your input in some 125 | * wrapper stream that limits reading. Despite usually reading the entire 126 | * input, this does not close the stream. 127 | */ 128 | - (id) mergeFromInputStream:(NSInputStream*) input; 129 | 130 | /** 131 | * Parse a message of this type from {@code input} and merge it with the 132 | * message being built. This is just a small wrapper around 133 | * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}. 134 | */ 135 | - (id) mergeFromInputStream:(NSInputStream*) input extensionRegistry:(PBExtensionRegistry*) extensionRegistry; 136 | @end 137 | -------------------------------------------------------------------------------- /ProtocolBuffers/MutableExtensionRegistry.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "ExtensionRegistry.h" 19 | 20 | @interface PBMutableExtensionRegistry : PBExtensionRegistry { 21 | @private 22 | NSMutableDictionary* mutableClassMap; 23 | } 24 | 25 | + (PBMutableExtensionRegistry*) registry; 26 | 27 | - (void) addExtension:(id) extension; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ProtocolBuffers/MutableExtensionRegistry.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "MutableExtensionRegistry.h" 19 | 20 | #import "ExtensionField.h" 21 | 22 | @interface PBMutableExtensionRegistry() 23 | @property (retain) NSMutableDictionary* mutableClassMap; 24 | @end 25 | 26 | @implementation PBMutableExtensionRegistry 27 | 28 | @synthesize mutableClassMap; 29 | 30 | - (void) dealloc { 31 | self.mutableClassMap = nil; 32 | [super dealloc]; 33 | } 34 | 35 | 36 | - (id) initWithClassMap:(NSMutableDictionary*) mutableClassMap_ { 37 | if ((self = [super initWithClassMap:mutableClassMap_])) { 38 | self.mutableClassMap = mutableClassMap_; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | 45 | + (PBMutableExtensionRegistry*) registry { 46 | return [[[PBMutableExtensionRegistry alloc] initWithClassMap:[NSMutableDictionary dictionary]] autorelease]; 47 | } 48 | 49 | 50 | - (void) addExtension:(id) extension { 51 | if (extension == nil) { 52 | return; 53 | } 54 | 55 | Class extendedClass = [extension extendedClass]; 56 | id key = [self keyForClass:extendedClass]; 57 | 58 | NSMutableDictionary* extensionMap = [classMap objectForKey:key]; 59 | if (extensionMap == nil) { 60 | extensionMap = [NSMutableDictionary dictionary]; 61 | [mutableClassMap setObject:extensionMap forKey:key]; 62 | } 63 | 64 | [extensionMap setObject:extension 65 | forKey:[NSNumber numberWithInteger:[extension fieldNumber]]]; 66 | } 67 | 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /ProtocolBuffers/MutableField.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Field.h" 19 | 20 | @class PBUnknownFieldSet; 21 | 22 | @interface PBMutableField : PBField 23 | 24 | + (PBMutableField *)field; 25 | 26 | - (PBMutableField *)mergeFromField:(PBField *)other; 27 | 28 | - (PBMutableField *)clear; 29 | - (PBMutableField *)addVarint:(int64_t)value; 30 | - (PBMutableField *)addFixed32:(int32_t)value; 31 | - (PBMutableField *)addFixed64:(int64_t)value; 32 | - (PBMutableField *)addLengthDelimited:(NSData *)value; 33 | - (PBMutableField *)addGroup:(PBUnknownFieldSet *)value; 34 | 35 | @end -------------------------------------------------------------------------------- /ProtocolBuffers/MutableField.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "MutableField.h" 19 | 20 | #import "Field.h" 21 | #import "PBArray.h" 22 | 23 | @implementation PBMutableField 24 | 25 | - (void)dealloc { 26 | [super dealloc]; 27 | } 28 | 29 | + (PBMutableField *)field { 30 | return [[[PBMutableField alloc] init] autorelease]; 31 | } 32 | 33 | - (PBMutableField *)clear { 34 | [_varintArray release]; _varintArray = nil; 35 | [_fixed32Array release]; _fixed32Array = nil; 36 | [_fixed64Array release]; _fixed64Array = nil; 37 | [_lengthDelimitedArray release]; _lengthDelimitedArray = nil; 38 | [_groupArray release]; _groupArray = nil; 39 | 40 | return self; 41 | } 42 | 43 | - (PBMutableField *)mergeFromField:(PBField *)other { 44 | if (other.varintArray.count > 0) { 45 | if (_varintArray == nil) { 46 | _varintArray = [other.varintArray copy]; 47 | } else { 48 | [_varintArray appendArray:other.varintArray]; 49 | } 50 | } 51 | 52 | if (other.fixed32Array.count > 0) { 53 | if (_fixed32Array == nil) { 54 | _fixed32Array = [other.fixed32Array copy]; 55 | } else { 56 | [_fixed32Array appendArray:other.fixed32Array]; 57 | } 58 | } 59 | 60 | if (other.fixed64Array.count > 0) { 61 | if (_fixed64Array == nil) { 62 | _fixed64Array = [other.fixed64Array copy]; 63 | } else { 64 | [_fixed64Array appendArray:other.fixed64Array]; 65 | } 66 | } 67 | 68 | if (other.lengthDelimitedArray.count > 0) { 69 | if (_lengthDelimitedArray == nil) { 70 | _lengthDelimitedArray = [other.lengthDelimitedArray copy]; 71 | } else { 72 | [_lengthDelimitedArray appendArray:other.lengthDelimitedArray]; 73 | } 74 | } 75 | 76 | if (other.groupArray.count > 0) { 77 | if (_groupArray == nil) { 78 | _groupArray = [other.groupArray copy]; 79 | } else { 80 | [_groupArray appendArray:other.groupArray]; 81 | } 82 | } 83 | 84 | return self; 85 | } 86 | 87 | - (PBMutableField *)addVarint:(int64_t)value { 88 | if (_varintArray == nil) { 89 | _varintArray = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt64]; 90 | } 91 | [_varintArray addInt64:value]; 92 | 93 | return self; 94 | } 95 | 96 | - (PBMutableField *)addFixed32:(int32_t)value { 97 | if (_fixed32Array == nil) { 98 | _fixed32Array = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt32]; 99 | } 100 | [_fixed32Array addInt32:value]; 101 | 102 | return self; 103 | } 104 | 105 | - (PBMutableField *)addFixed64:(int64_t)value { 106 | if (_fixed64Array == nil) { 107 | _fixed64Array = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeInt64]; 108 | } 109 | [_fixed64Array addInt64:value]; 110 | 111 | return self; 112 | } 113 | 114 | - (PBMutableField *)addLengthDelimited:(NSData *)value { 115 | if (_lengthDelimitedArray == nil) { 116 | _lengthDelimitedArray = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeObject]; 117 | } 118 | [_lengthDelimitedArray addObject:value]; 119 | 120 | return self; 121 | } 122 | 123 | - (PBMutableField *)addGroup:(PBUnknownFieldSet *)value { 124 | if (_groupArray == nil) { 125 | _groupArray = [[PBAppendableArray alloc] initWithValueType:PBArrayValueTypeObject]; 126 | } 127 | [_groupArray addObject:value]; 128 | 129 | return self; 130 | } 131 | 132 | @end -------------------------------------------------------------------------------- /ProtocolBuffers/PBArray.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // 9 | // http://www.apache.org/licenses/LICENSE-2.0 10 | // 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | // 17 | // Author: Jon Parise 18 | 19 | #import 20 | 21 | extern NSString * const PBArrayTypeMismatchException; 22 | extern NSString * const PBArrayNumberExpectedException; 23 | extern NSString * const PBArrayAllocationFailureException; 24 | 25 | typedef enum _PBArrayValueType 26 | { 27 | PBArrayValueTypeObject, 28 | PBArrayValueTypeBool, 29 | PBArrayValueTypeInt32, 30 | PBArrayValueTypeUInt32, 31 | PBArrayValueTypeInt64, 32 | PBArrayValueTypeUInt64, 33 | PBArrayValueTypeFloat, 34 | PBArrayValueTypeDouble, 35 | } PBArrayValueType; 36 | 37 | // PBArray is an immutable array class that's optimized for storing primitive 38 | // values. All values stored in an PBArray instance must have the same type 39 | // (PBArrayValueType). Object values (PBArrayValueTypeObject) are retained. 40 | @interface PBArray : NSObject 41 | { 42 | @protected 43 | PBArrayValueType _valueType; 44 | NSUInteger _capacity; 45 | NSUInteger _count; 46 | void * _data; 47 | } 48 | 49 | - (NSUInteger)count; 50 | - (id)objectAtIndex:(NSUInteger)index; 51 | - (BOOL)boolAtIndex:(NSUInteger)index; 52 | - (int32_t)int32AtIndex:(NSUInteger)index; 53 | - (uint32_t)uint32AtIndex:(NSUInteger)index; 54 | - (int64_t)int64AtIndex:(NSUInteger)index; 55 | - (uint64_t)uint64AtIndex:(NSUInteger)index; 56 | - (Float32)floatAtIndex:(NSUInteger)index; 57 | - (Float64)doubleAtIndex:(NSUInteger)index; 58 | - (BOOL)isEqualToArray:(PBArray *)array; 59 | 60 | @property (nonatomic,assign,readonly) PBArrayValueType valueType; 61 | @property (nonatomic,assign,readonly) const void * data; 62 | @property (nonatomic,assign,readonly,getter=count) NSUInteger count; 63 | 64 | @end 65 | 66 | @interface PBArray (PBArrayExtended) 67 | 68 | - (id)arrayByAppendingArray:(PBArray *)array; 69 | 70 | @end 71 | 72 | @interface PBArray (PBArrayCreation) 73 | 74 | + (id)arrayWithValueType:(PBArrayValueType)valueType; 75 | + (id)arrayWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType; 76 | + (id)arrayWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType; 77 | - (id)initWithValueType:(PBArrayValueType)valueType; 78 | - (id)initWithValues:(const void *)values count:(NSUInteger)count valueType:(PBArrayValueType)valueType; 79 | - (id)initWithArray:(NSArray *)array valueType:(PBArrayValueType)valueType; 80 | 81 | @end 82 | 83 | // PBAppendableArray extends PBArray with the ability to append new values to 84 | // the end of the array. 85 | @interface PBAppendableArray : PBArray 86 | 87 | - (void)addObject:(id)value; 88 | - (void)addBool:(BOOL)value; 89 | - (void)addInt32:(int32_t)value; 90 | - (void)addUint32:(uint32_t)value; 91 | - (void)addInt64:(int64_t)value; 92 | - (void)addUint64:(uint64_t)value; 93 | - (void)addFloat:(Float32)value; 94 | - (void)addDouble:(Float64)value; 95 | 96 | - (void)appendArray:(PBArray *)array; 97 | - (void)appendValues:(const void *)values count:(NSUInteger)count; 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /ProtocolBuffers/ProtocolBuffers-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.apple.server.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ProtocolBuffers/ProtocolBuffers-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'ProtocolBuffers' target in the 'ProtocolBuffers' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | 9 | -------------------------------------------------------------------------------- /ProtocolBuffers/ProtocolBuffers.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Bootstrap.h" 19 | 20 | #import "AbstractMessage.h" 21 | #import "AbstractMessage_Builder.h" 22 | #import "CodedInputStream.h" 23 | #import "CodedOutputStream.h" 24 | #import "ConcreteExtensionField.h" 25 | #import "ExtendableMessage.h" 26 | #import "ExtendableMessage_Builder.h" 27 | #import "ExtensionField.h" 28 | #import "ExtensionRegistry.h" 29 | #import "Field.h" 30 | #import "GeneratedMessage.h" 31 | #import "GeneratedMessage_Builder.h" 32 | #import "Message.h" 33 | #import "Message_Builder.h" 34 | #import "MutableExtensionRegistry.h" 35 | #import "MutableField.h" 36 | #import "PBArray.h" 37 | #import "UnknownFieldSet.h" 38 | #import "UnknownFieldSet_Builder.h" 39 | #import "Utilities.h" 40 | #import "WireFormat.h" -------------------------------------------------------------------------------- /ProtocolBuffers/RingBuffer.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RingBuffer : NSObject { 4 | NSMutableData *buffer; 5 | NSInteger position; 6 | NSInteger tail; 7 | } 8 | @property (nonatomic, readonly) NSUInteger freeSpace; 9 | 10 | - (id)initWithData:(NSMutableData*)data; 11 | 12 | // Returns false if there is not enough free space in buffer 13 | - (BOOL)appendByte:(uint8_t)byte; 14 | 15 | // Returns number of bytes written 16 | - (NSInteger)appendData:(const NSData*)value offset:(NSInteger)offset length:(NSInteger)length; 17 | 18 | // Returns number of bytes written 19 | - (NSInteger)flushToOutputStream:(NSOutputStream*)stream; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /ProtocolBuffers/RingBuffer.m: -------------------------------------------------------------------------------- 1 | #import "RingBuffer.h" 2 | 3 | @implementation RingBuffer 4 | 5 | - (id)initWithData:(NSMutableData*)data { 6 | if ((self = [super init])) { 7 | buffer = [data retain]; 8 | } 9 | return self; 10 | } 11 | 12 | 13 | - (NSUInteger)freeSpace { 14 | return (position < tail ? tail - position : (buffer.length - position) + tail) - (tail ? 1 : 0); 15 | } 16 | 17 | 18 | - (BOOL)appendByte:(uint8_t)byte { 19 | if (self.freeSpace < 1) return NO; 20 | ((uint8_t*)buffer.mutableBytes)[position++] = byte; 21 | return YES; 22 | } 23 | 24 | 25 | - (NSInteger)appendData:(const NSData*)value offset:(NSInteger)offset length:(NSInteger)length { 26 | NSInteger totalWritten = 0; 27 | const uint8_t *input = value.bytes; 28 | uint8_t *data = buffer.mutableBytes; 29 | 30 | if (position >= tail) { 31 | totalWritten = MIN(buffer.length - position, length); 32 | memcpy(data + position, input + offset, totalWritten); 33 | position += totalWritten; 34 | if (totalWritten == length) return length; 35 | length -= totalWritten; 36 | offset += totalWritten; 37 | } 38 | 39 | NSUInteger freeSpace = self.freeSpace; 40 | if (!freeSpace) return totalWritten; 41 | 42 | if (position == buffer.length) { 43 | position = 0; 44 | } 45 | 46 | // position < tail 47 | int32_t written = MIN(freeSpace, length); 48 | memcpy(data + position, input + offset, written); 49 | position += written; 50 | totalWritten += written; 51 | 52 | return totalWritten; 53 | } 54 | 55 | 56 | - (NSInteger)flushToOutputStream:(NSOutputStream*)stream { 57 | NSInteger totalWritten = 0; 58 | const uint8_t *data = buffer.bytes; 59 | 60 | if (tail > position) { 61 | int32_t written = [stream write:data + tail maxLength:buffer.length - tail]; 62 | if (written <= 0) return totalWritten; 63 | totalWritten += written; 64 | tail += written; 65 | if (tail == buffer.length) { 66 | tail = 0; 67 | } 68 | } 69 | 70 | if (tail < position) { 71 | int32_t written = [stream write:data + tail maxLength:position - tail]; 72 | if (written <= 0) return totalWritten; 73 | totalWritten += written; 74 | tail += written; 75 | } 76 | 77 | if (tail == position) { 78 | tail = position = 0; 79 | } 80 | 81 | if (position == buffer.length && tail > 0) { 82 | position = 0; 83 | } 84 | 85 | if (tail == buffer.length) { 86 | tail = 0; 87 | } 88 | 89 | return totalWritten; 90 | } 91 | 92 | 93 | - (void)dealloc { 94 | [buffer release]; 95 | [super dealloc]; 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /ProtocolBuffers/TextFormat.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | @interface PBTextFormat : NSObject { 19 | 20 | } 21 | 22 | + (int32_t) parseInt32:(NSString*) text; 23 | + (int32_t) parseUInt32:(NSString*) text; 24 | + (int64_t) parseInt64:(NSString*) text; 25 | + (int64_t) parseUInt64:(NSString*) text; 26 | 27 | + (NSData*) unescapeBytes:(NSString*) input; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ProtocolBuffers/UnknownFieldSet.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | @class PBCodedOutputStream; 19 | @class PBField; 20 | @class PBUnknownFieldSet_Builder; 21 | 22 | @interface PBUnknownFieldSet : NSObject { 23 | @private 24 | NSDictionary* fields; 25 | } 26 | 27 | @property (readonly, retain) NSDictionary* fields; 28 | 29 | + (PBUnknownFieldSet*) defaultInstance; 30 | 31 | + (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields; 32 | + (PBUnknownFieldSet*) parseFromData:(NSData*) data; 33 | 34 | + (PBUnknownFieldSet_Builder*) builder; 35 | + (PBUnknownFieldSet_Builder*) builderWithUnknownFields:(PBUnknownFieldSet*) other; 36 | 37 | - (void) writeAsMessageSetTo:(PBCodedOutputStream*) output; 38 | - (void) writeToCodedOutputStream:(PBCodedOutputStream*) output; 39 | - (NSData*) data; 40 | 41 | - (int32_t) serializedSize; 42 | - (int32_t) serializedSizeAsMessageSet; 43 | 44 | - (BOOL) hasField:(int32_t) number; 45 | - (PBField*) getField:(int32_t) number; 46 | 47 | - (void) writeDescriptionTo:(NSMutableString*) output 48 | withIndent:(NSString*) indent; 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /ProtocolBuffers/UnknownFieldSet.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "UnknownFieldSet.h" 19 | 20 | #import "CodedInputStream.h" 21 | #import "CodedOutputStream.h" 22 | #import "Field.h" 23 | #import "UnknownFieldSet_Builder.h" 24 | 25 | @interface PBUnknownFieldSet() 26 | @property (retain) NSDictionary* fields; 27 | @end 28 | 29 | 30 | @implementation PBUnknownFieldSet 31 | 32 | static PBUnknownFieldSet* defaultInstance = nil; 33 | 34 | + (void) initialize { 35 | if (self == [PBUnknownFieldSet class]) { 36 | defaultInstance = [[PBUnknownFieldSet setWithFields:[NSMutableDictionary dictionary]] retain]; 37 | } 38 | } 39 | 40 | 41 | @synthesize fields; 42 | 43 | - (void) dealloc { 44 | self.fields = nil; 45 | 46 | [super dealloc]; 47 | } 48 | 49 | 50 | + (PBUnknownFieldSet*) defaultInstance { 51 | return defaultInstance; 52 | } 53 | 54 | 55 | - (id) initWithFields:(NSMutableDictionary*) fields_ { 56 | if ((self = [super init])) { 57 | self.fields = fields_; 58 | } 59 | 60 | return self; 61 | } 62 | 63 | 64 | + (PBUnknownFieldSet*) setWithFields:(NSMutableDictionary*) fields { 65 | return [[[PBUnknownFieldSet alloc] initWithFields:fields] autorelease]; 66 | } 67 | 68 | 69 | - (BOOL) hasField:(int32_t) number { 70 | return [fields objectForKey:[NSNumber numberWithInt:number]] != nil; 71 | } 72 | 73 | 74 | - (PBField*) getField:(int32_t) number { 75 | PBField* result = [fields objectForKey:[NSNumber numberWithInt:number]]; 76 | return (result == nil) ? [PBField defaultInstance] : result; 77 | } 78 | 79 | 80 | - (void) writeToCodedOutputStream:(PBCodedOutputStream*) output { 81 | NSArray* sortedKeys = [fields.allKeys sortedArrayUsingSelector:@selector(compare:)]; 82 | for (NSNumber* number in sortedKeys) { 83 | PBField* value = [fields objectForKey:number]; 84 | [value writeTo:number.intValue output:output]; 85 | } 86 | } 87 | 88 | 89 | - (void) writeToOutputStream:(NSOutputStream*) output { 90 | PBCodedOutputStream* codedOutput = [PBCodedOutputStream streamWithOutputStream:output]; 91 | [self writeToCodedOutputStream:codedOutput]; 92 | [codedOutput flush]; 93 | } 94 | 95 | 96 | - (void) writeDescriptionTo:(NSMutableString*) output 97 | withIndent:(NSString *)indent { 98 | NSArray* sortedKeys = [fields.allKeys sortedArrayUsingSelector:@selector(compare:)]; 99 | for (NSNumber* number in sortedKeys) { 100 | PBField* value = [fields objectForKey:number]; 101 | [value writeDescriptionFor:number.intValue to:output withIndent:indent]; 102 | } 103 | } 104 | 105 | 106 | + (PBUnknownFieldSet*) parseFromCodedInputStream:(PBCodedInputStream*) input { 107 | return [[[PBUnknownFieldSet builder] mergeFromCodedInputStream:input] build]; 108 | } 109 | 110 | 111 | + (PBUnknownFieldSet*) parseFromData:(NSData*) data { 112 | return [[[PBUnknownFieldSet builder] mergeFromData:data] build]; 113 | } 114 | 115 | 116 | + (PBUnknownFieldSet*) parseFromInputStream:(NSInputStream*) input { 117 | return [[[PBUnknownFieldSet builder] mergeFromInputStream:input] build]; 118 | } 119 | 120 | 121 | + (PBUnknownFieldSet_Builder*) builder { 122 | return [[[PBUnknownFieldSet_Builder alloc] init] autorelease]; 123 | } 124 | 125 | 126 | + (PBUnknownFieldSet_Builder*) builderWithUnknownFields:(PBUnknownFieldSet*) copyFrom { 127 | return [[PBUnknownFieldSet builder] mergeUnknownFields:copyFrom]; 128 | } 129 | 130 | 131 | /** Get the number of bytes required to encode this set. */ 132 | - (int32_t) serializedSize { 133 | int32_t result = 0; 134 | for (NSNumber* number in fields) { 135 | result += [[fields objectForKey:number] getSerializedSize:number.intValue]; 136 | } 137 | return result; 138 | } 139 | 140 | /** 141 | * Serializes the set and writes it to {@code output} using 142 | * {@code MessageSet} wire format. 143 | */ 144 | - (void) writeAsMessageSetTo:(PBCodedOutputStream*) output { 145 | for (NSNumber* number in fields) { 146 | [[fields objectForKey:number] writeAsMessageSetExtensionTo:number.intValue output:output]; 147 | } 148 | } 149 | 150 | 151 | /** 152 | * Get the number of bytes required to encode this set using 153 | * {@code MessageSet} wire format. 154 | */ 155 | - (int32_t) serializedSizeAsMessageSet { 156 | int32_t result = 0; 157 | for (NSNumber* number in fields) { 158 | result += [[fields objectForKey:number] getSerializedSizeAsMessageSetExtension:number.intValue]; 159 | } 160 | return result; 161 | } 162 | 163 | 164 | /** 165 | * Serializes the message to a {@code ByteString} and returns it. This is 166 | * just a trivial wrapper around {@link #writeTo(PBCodedOutputStream)}. 167 | */ 168 | - (NSData*) data { 169 | NSMutableData* data = [NSMutableData dataWithLength:self.serializedSize]; 170 | PBCodedOutputStream* output = [PBCodedOutputStream streamWithData:data]; 171 | 172 | [self writeToCodedOutputStream:output]; 173 | return data; 174 | } 175 | 176 | @end 177 | -------------------------------------------------------------------------------- /ProtocolBuffers/UnknownFieldSet_Builder.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "Message_Builder.h" 19 | 20 | @class PBField; 21 | @class PBMutableField; 22 | 23 | @interface PBUnknownFieldSet_Builder : NSObject { 24 | @private 25 | NSMutableDictionary* fields; 26 | 27 | // Optimization: We keep around a builder for the last field that was 28 | // modified so that we can efficiently add to it multiple times in a 29 | // row (important when parsing an unknown repeated field). 30 | int32_t lastFieldNumber; 31 | 32 | PBMutableField* lastField; 33 | } 34 | 35 | + (PBUnknownFieldSet_Builder*) createBuilder:(PBUnknownFieldSet*) unknownFields; 36 | 37 | - (PBUnknownFieldSet*) build; 38 | - (PBUnknownFieldSet_Builder*) mergeUnknownFields:(PBUnknownFieldSet*) other; 39 | 40 | - (PBUnknownFieldSet_Builder*) mergeFromCodedInputStream:(PBCodedInputStream*) input; 41 | - (PBUnknownFieldSet_Builder*) mergeFromData:(NSData*) data; 42 | - (PBUnknownFieldSet_Builder*) mergeFromInputStream:(NSInputStream*) input; 43 | 44 | - (PBUnknownFieldSet_Builder*) mergeVarintField:(int32_t) number value:(int32_t) value; 45 | 46 | - (BOOL) mergeFieldFrom:(int32_t) tag input:(PBCodedInputStream*) input; 47 | 48 | - (PBUnknownFieldSet_Builder*) addField:(PBField*) field forNumber:(int32_t) number; 49 | 50 | - (PBUnknownFieldSet_Builder*) clear; 51 | - (PBUnknownFieldSet_Builder*) mergeField:(PBField*) field forNumber:(int32_t) number; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /ProtocolBuffers/WireFormat.h: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | typedef enum { 19 | PBWireFormatVarint = 0, 20 | PBWireFormatFixed64 = 1, 21 | PBWireFormatLengthDelimited = 2, 22 | PBWireFormatStartGroup = 3, 23 | PBWireFormatEndGroup = 4, 24 | PBWireFormatFixed32 = 5, 25 | 26 | PBWireFormatTagTypeBits = 3, 27 | PBWireFormatTagTypeMask = 7 /* = (1 << PBWireFormatTagTypeBits) - 1*/, 28 | 29 | PBWireFormatMessageSetItem = 1, 30 | PBWireFormatMessageSetTypeId = 2, 31 | PBWireFormatMessageSetMessage = 3 32 | } PBWireFormat; 33 | 34 | int32_t PBWireFormatMakeTag(int32_t fieldNumber, int32_t wireType); 35 | int32_t PBWireFormatGetTagWireType(int32_t tag); 36 | int32_t PBWireFormatGetTagFieldNumber(int32_t tag); 37 | 38 | #define PBWireFormatMessageSetItemTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatStartGroup)) 39 | #define PBWireFormatMessageSetItemEndTag (PBWireFormatMakeTag(PBWireFormatMessageSetItem, PBWireFormatEndGroup)) 40 | #define PBWireFormatMessageSetTypeIdTag (PBWireFormatMakeTag(PBWireFormatMessageSetTypeId, PBWireFormatVarint)) 41 | #define PBWireFormatMessageSetMessageTag (PBWireFormatMakeTag(PBWireFormatMessageSetMessage, PBWireFormatLengthDelimited)) 42 | -------------------------------------------------------------------------------- /ProtocolBuffers/WireFormat.m: -------------------------------------------------------------------------------- 1 | // Protocol Buffers for Objective C 2 | // 3 | // Copyright 2010 Booyah Inc. 4 | // Copyright 2008 Cyrus Najmabadi 5 | // 6 | // Licensed under the Apache License, Version 2.0 (the "License"); 7 | // you may not use this file except in compliance with the License. 8 | // You may obtain a copy of the License at 9 | // 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // 12 | // Unless required by applicable law or agreed to in writing, software 13 | // distributed under the License is distributed on an "AS IS" BASIS, 14 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | // See the License for the specific language governing permissions and 16 | // limitations under the License. 17 | 18 | #import "WireFormat.h" 19 | 20 | #import "Utilities.h" 21 | 22 | int32_t PBWireFormatMakeTag(int32_t fieldNumber, int32_t wireType) { 23 | return (fieldNumber << PBWireFormatTagTypeBits) | wireType; 24 | } 25 | 26 | 27 | int32_t PBWireFormatGetTagWireType(int32_t tag) { 28 | return tag & PBWireFormatTagTypeMask; 29 | } 30 | 31 | 32 | int32_t PBWireFormatGetTagFieldNumber(int32_t tag) { 33 | return logicalRightShift32(tag, PBWireFormatTagTypeBits); 34 | } 35 | -------------------------------------------------------------------------------- /ProtocolBuffers/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Routing HTTP Server/HTTPResponseProxy.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | 4 | // Wraps an HTTPResponse object to allow setting a custom status code 5 | // without needing to create subclasses of every response. 6 | @interface HTTPResponseProxy : NSObject 7 | 8 | @property (nonatomic) NSObject *response; 9 | @property (nonatomic) NSInteger status; 10 | 11 | - (NSInteger)customStatus; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Routing HTTP Server/HTTPResponseProxy.m: -------------------------------------------------------------------------------- 1 | #import "HTTPResponseProxy.h" 2 | 3 | @implementation HTTPResponseProxy 4 | 5 | @synthesize response; 6 | @synthesize status; 7 | 8 | - (NSInteger)status { 9 | if (status != 0) { 10 | return status; 11 | } else if ([response respondsToSelector:@selector(status)]) { 12 | return [response status]; 13 | } 14 | 15 | return 200; 16 | } 17 | 18 | - (void)setStatus:(NSInteger)statusCode { 19 | status = statusCode; 20 | } 21 | 22 | - (NSInteger)customStatus { 23 | return status; 24 | } 25 | 26 | // Implement the required HTTPResponse methods 27 | - (UInt64)contentLength { 28 | if (response) { 29 | return [response contentLength]; 30 | } else { 31 | return 0; 32 | } 33 | } 34 | 35 | - (UInt64)offset { 36 | if (response) { 37 | return [response offset]; 38 | } else { 39 | return 0; 40 | } 41 | } 42 | 43 | - (void)setOffset:(UInt64)offset { 44 | if (response) { 45 | [response setOffset:offset]; 46 | } 47 | } 48 | 49 | - (NSData *)readDataOfLength:(NSUInteger)length { 50 | if (response) { 51 | return [response readDataOfLength:length]; 52 | } else { 53 | return nil; 54 | } 55 | } 56 | 57 | - (BOOL)isDone { 58 | if (response) { 59 | return [response isDone]; 60 | } else { 61 | return YES; 62 | } 63 | } 64 | 65 | // Forward all other invocations to the actual response object 66 | - (void)forwardInvocation:(NSInvocation *)invocation { 67 | if ([response respondsToSelector:[invocation selector]]) { 68 | [invocation invokeWithTarget:response]; 69 | } else { 70 | [super forwardInvocation:invocation]; 71 | } 72 | } 73 | 74 | - (BOOL)respondsToSelector:(SEL)selector { 75 | if ([super respondsToSelector:selector]) 76 | return YES; 77 | 78 | return [response respondsToSelector:selector]; 79 | } 80 | 81 | @end 82 | 83 | -------------------------------------------------------------------------------- /Routing HTTP Server/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011-2012 Matt Stevens 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Routing HTTP Server/Route.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "RoutingHTTPServer.h" 3 | 4 | @interface Route : NSObject 5 | 6 | @property (nonatomic) NSRegularExpression *regex; 7 | @property (nonatomic, copy) RequestHandler handler; 8 | @property (nonatomic, weak) id target; 9 | @property (nonatomic, assign) SEL selector; 10 | @property (nonatomic) NSArray *keys; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Routing HTTP Server/Route.m: -------------------------------------------------------------------------------- 1 | #import "Route.h" 2 | 3 | @implementation Route 4 | 5 | @synthesize regex; 6 | @synthesize handler; 7 | @synthesize target; 8 | @synthesize selector; 9 | @synthesize keys; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Routing HTTP Server/RouteRequest.h: -------------------------------------------------------------------------------- 1 | #import 2 | @class HTTPMessage; 3 | 4 | @interface RouteRequest : NSObject 5 | 6 | @property (nonatomic, readonly) NSDictionary *headers; 7 | @property (nonatomic, readonly) NSDictionary *params; 8 | 9 | - (id)initWithHTTPMessage:(HTTPMessage *)msg parameters:(NSDictionary *)params; 10 | - (NSString *)header:(NSString *)field; 11 | - (id)param:(NSString *)name; 12 | - (NSString *)method; 13 | - (NSURL *)url; 14 | - (NSData *)body; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Routing HTTP Server/RouteRequest.m: -------------------------------------------------------------------------------- 1 | #import "RouteRequest.h" 2 | #import "HTTPMessage.h" 3 | 4 | @implementation RouteRequest { 5 | HTTPMessage *message; 6 | } 7 | 8 | @synthesize params; 9 | 10 | - (id)initWithHTTPMessage:(HTTPMessage *)msg parameters:(NSDictionary *)parameters { 11 | if (self = [super init]) { 12 | params = parameters; 13 | message = msg; 14 | } 15 | return self; 16 | } 17 | 18 | - (NSDictionary *)headers { 19 | return [message allHeaderFields]; 20 | } 21 | 22 | - (NSString *)header:(NSString *)field { 23 | return [message headerField:field]; 24 | } 25 | 26 | - (id)param:(NSString *)name { 27 | return [params objectForKey:name]; 28 | } 29 | 30 | - (NSString *)method { 31 | return [message method]; 32 | } 33 | 34 | - (NSURL *)url { 35 | return [message url]; 36 | } 37 | 38 | - (NSData *)body { 39 | return [message body]; 40 | } 41 | 42 | - (NSString *)description { 43 | NSData *data = [message messageData]; 44 | return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /Routing HTTP Server/RouteResponse.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPResponse.h" 3 | @class HTTPConnection; 4 | @class HTTPResponseProxy; 5 | 6 | @interface RouteResponse : NSObject 7 | 8 | @property (nonatomic, weak, readonly) HTTPConnection *connection; 9 | @property (nonatomic, readonly) NSDictionary *headers; 10 | @property (nonatomic, strong) NSObject *response; 11 | @property (nonatomic, readonly) NSObject *proxiedResponse; 12 | @property (nonatomic) NSInteger statusCode; 13 | 14 | - (id)initWithConnection:(HTTPConnection *)theConnection; 15 | - (void)setHeader:(NSString *)field value:(NSString *)value; 16 | - (void)respondWithString:(NSString *)string; 17 | - (void)respondWithString:(NSString *)string encoding:(NSStringEncoding)encoding; 18 | - (void)respondWithData:(NSData *)data; 19 | - (void)respondWithFile:(NSString *)path; 20 | - (void)respondWithFile:(NSString *)path async:(BOOL)async; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Routing HTTP Server/RouteResponse.m: -------------------------------------------------------------------------------- 1 | #import "RouteResponse.h" 2 | #import "HTTPConnection.h" 3 | #import "HTTPDataResponse.h" 4 | #import "HTTPFileResponse.h" 5 | #import "HTTPAsyncFileResponse.h" 6 | #import "HTTPResponseProxy.h" 7 | 8 | @implementation RouteResponse { 9 | NSMutableDictionary *headers; 10 | HTTPResponseProxy *proxy; 11 | } 12 | 13 | @synthesize connection; 14 | @synthesize headers; 15 | 16 | - (id)initWithConnection:(HTTPConnection *)theConnection { 17 | if (self = [super init]) { 18 | connection = theConnection; 19 | headers = [[NSMutableDictionary alloc] init]; 20 | proxy = [[HTTPResponseProxy alloc] init]; 21 | } 22 | return self; 23 | } 24 | 25 | - (NSObject *)response { 26 | return proxy.response; 27 | } 28 | 29 | - (void)setResponse:(NSObject *)response { 30 | proxy.response = response; 31 | } 32 | 33 | - (NSObject *)proxiedResponse { 34 | if (proxy.response != nil || proxy.customStatus != 0 || [headers count] > 0) { 35 | return proxy; 36 | } 37 | 38 | return nil; 39 | } 40 | 41 | - (NSInteger)statusCode { 42 | return proxy.status; 43 | } 44 | 45 | - (void)setStatusCode:(NSInteger)status { 46 | proxy.status = status; 47 | } 48 | 49 | - (void)setHeader:(NSString *)field value:(NSString *)value { 50 | [headers setObject:value forKey:field]; 51 | } 52 | 53 | - (void)respondWithString:(NSString *)string { 54 | [self respondWithString:string encoding:NSUTF8StringEncoding]; 55 | } 56 | 57 | - (void)respondWithString:(NSString *)string encoding:(NSStringEncoding)encoding { 58 | [self respondWithData:[string dataUsingEncoding:encoding]]; 59 | } 60 | 61 | - (void)respondWithData:(NSData *)data { 62 | self.response = [[HTTPDataResponse alloc] initWithData:data]; 63 | } 64 | 65 | - (void)respondWithFile:(NSString *)path { 66 | [self respondWithFile:path async:NO]; 67 | } 68 | 69 | - (void)respondWithFile:(NSString *)path async:(BOOL)async { 70 | if (async) { 71 | self.response = [[HTTPAsyncFileResponse alloc] initWithFilePath:path forConnection:connection]; 72 | } else { 73 | self.response = [[HTTPFileResponse alloc] initWithFilePath:path forConnection:connection]; 74 | } 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /Routing HTTP Server/RoutingConnection.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "HTTPConnection.h" 3 | @class RoutingHTTPServer; 4 | 5 | @interface RoutingConnection : HTTPConnection 6 | @end 7 | -------------------------------------------------------------------------------- /Routing HTTP Server/RoutingConnection.m: -------------------------------------------------------------------------------- 1 | #import "RoutingConnection.h" 2 | #import "RoutingHTTPServer.h" 3 | #import "HTTPMessage.h" 4 | #import "HTTPResponseProxy.h" 5 | #import "RouteRequest.h" 6 | #import "RouteResponse.h" 7 | 8 | @implementation RoutingConnection { 9 | __weak RoutingHTTPServer *http; 10 | NSDictionary *headers; 11 | } 12 | 13 | - (id)initWithAsyncSocket:(GCDAsyncSocket *)newSocket configuration:(HTTPConfig *)aConfig { 14 | if (self = [super initWithAsyncSocket:newSocket configuration:aConfig]) { 15 | NSAssert([config.server isKindOfClass:[RoutingHTTPServer class]], 16 | @"A RoutingConnection is being used with a server that is not a RoutingHTTPServer"); 17 | 18 | http = (RoutingHTTPServer *)config.server; 19 | } 20 | return self; 21 | } 22 | 23 | - (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path { 24 | 25 | if ([http supportsMethod:method]) 26 | return YES; 27 | 28 | return [super supportsMethod:method atPath:path]; 29 | } 30 | 31 | - (BOOL)shouldHandleRequestForMethod:(NSString *)method atPath:(NSString *)path { 32 | // The default implementation is strict about the use of Content-Length. Either 33 | // a given method + path combination must *always* include data or *never* 34 | // include data. The routing connection is lenient, a POST that sometimes does 35 | // not include data or a GET that sometimes does is fine. It is up to the route 36 | // implementations to decide how to handle these situations. 37 | return YES; 38 | } 39 | 40 | - (void)processBodyData:(NSData *)postDataChunk { 41 | BOOL result = [request appendData:postDataChunk]; 42 | if (!result) { 43 | // TODO: Log 44 | } 45 | } 46 | 47 | - (NSObject *)httpResponseForMethod:(NSString *)method URI:(NSString *)path { 48 | NSURL *url = [request url]; 49 | NSString *query = nil; 50 | NSDictionary *params = [NSDictionary dictionary]; 51 | headers = nil; 52 | 53 | if (url) { 54 | path = [url path]; // Strip the query string from the path 55 | query = [url query]; 56 | if (query) { 57 | params = [self parseParams:query]; 58 | } 59 | } 60 | 61 | RouteResponse *response = [http routeMethod:method withPath:path parameters:params request:request connection:self]; 62 | if (response != nil) { 63 | headers = response.headers; 64 | return response.proxiedResponse; 65 | } 66 | 67 | // Set a MIME type for static files if possible 68 | NSObject *staticResponse = [super httpResponseForMethod:method URI:path]; 69 | if (staticResponse && [staticResponse respondsToSelector:@selector(filePath)]) { 70 | NSString *mimeType = [http mimeTypeForPath:[staticResponse performSelector:@selector(filePath)]]; 71 | if (mimeType) { 72 | headers = [NSDictionary dictionaryWithObject:mimeType forKey:@"Content-Type"]; 73 | } 74 | } 75 | return staticResponse; 76 | } 77 | 78 | - (void)responseHasAvailableData:(NSObject *)sender { 79 | HTTPResponseProxy *proxy = (HTTPResponseProxy *)httpResponse; 80 | if (proxy.response == sender) { 81 | [super responseHasAvailableData:httpResponse]; 82 | } 83 | } 84 | 85 | - (void)responseDidAbort:(NSObject *)sender { 86 | HTTPResponseProxy *proxy = (HTTPResponseProxy *)httpResponse; 87 | if (proxy.response == sender) { 88 | [super responseDidAbort:httpResponse]; 89 | } 90 | } 91 | 92 | - (void)setHeadersForResponse:(HTTPMessage *)response isError:(BOOL)isError { 93 | [http.defaultHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL *stop) { 94 | [response setHeaderField:field value:value]; 95 | }]; 96 | 97 | if (headers && !isError) { 98 | [headers enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL *stop) { 99 | [response setHeaderField:field value:value]; 100 | }]; 101 | } 102 | 103 | // Set the connection header if not already specified 104 | NSString *connection = [response headerField:@"Connection"]; 105 | if (!connection) { 106 | connection = [self shouldDie] ? @"close" : @"keep-alive"; 107 | [response setHeaderField:@"Connection" value:connection]; 108 | } 109 | } 110 | 111 | - (NSData *)preprocessResponse:(HTTPMessage *)response { 112 | [self setHeadersForResponse:response isError:NO]; 113 | return [super preprocessResponse:response]; 114 | } 115 | 116 | - (NSData *)preprocessErrorResponse:(HTTPMessage *)response { 117 | [self setHeadersForResponse:response isError:YES]; 118 | return [super preprocessErrorResponse:response]; 119 | } 120 | 121 | - (BOOL)shouldDie { 122 | __block BOOL shouldDie = [super shouldDie]; 123 | 124 | // Allow custom headers to determine if the connection should be closed 125 | if (!shouldDie && headers) { 126 | [headers enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL *stop) { 127 | if ([field caseInsensitiveCompare:@"connection"] == NSOrderedSame) { 128 | if ([value caseInsensitiveCompare:@"close"] == NSOrderedSame) { 129 | shouldDie = YES; 130 | } 131 | *stop = YES; 132 | } 133 | }]; 134 | } 135 | 136 | return shouldDie; 137 | } 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /Routing HTTP Server/RoutingHTTPServer.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CocoaHTTPServer.h" 3 | #import "RouteRequest.h" 4 | #import "RouteResponse.h" 5 | 6 | typedef void (^RequestHandler)(RouteRequest *request, RouteResponse *response); 7 | 8 | @interface RoutingHTTPServer : HTTPServer 9 | 10 | @property (nonatomic, readonly) NSDictionary *defaultHeaders; 11 | 12 | // Specifies headers that will be set on every response. 13 | // These headers can be overridden by RouteResponses. 14 | - (void)setDefaultHeaders:(NSDictionary *)headers; 15 | - (void)setDefaultHeader:(NSString *)field value:(NSString *)value; 16 | 17 | // Returns the dispatch queue on which routes are processed. 18 | // By default this is NULL and routes are processed on CocoaHTTPServer's 19 | // connection queue. You can specify a queue to process routes on, such as 20 | // dispatch_get_main_queue() to process all routes on the main thread. 21 | - (dispatch_queue_t)routeQueue; 22 | - (void)setRouteQueue:(dispatch_queue_t)queue; 23 | 24 | - (NSDictionary *)mimeTypes; 25 | - (void)setMIMETypes:(NSDictionary *)types; 26 | - (void)setMIMEType:(NSString *)type forExtension:(NSString *)ext; 27 | - (NSString *)mimeTypeForPath:(NSString *)path; 28 | 29 | // Convenience methods. Yes I know, this is Cocoa and we don't use convenience 30 | // methods because typing lengthy primitives over and over and over again is 31 | // elegant with the beauty and the poetry. These are just, you know, here. 32 | - (void)get:(NSString *)path withBlock:(RequestHandler)block; 33 | - (void)post:(NSString *)path withBlock:(RequestHandler)block; 34 | - (void)put:(NSString *)path withBlock:(RequestHandler)block; 35 | - (void)delete:(NSString *)path withBlock:(RequestHandler)block; 36 | - (void)subscribe:(NSString *)path withBlock:(RequestHandler)block; 37 | - (void)unsubscribe:(NSString *)path withBlock:(RequestHandler)block; 38 | 39 | - (void)handleMethod:(NSString *)method withPath:(NSString *)path block:(RequestHandler)block; 40 | - (void)handleMethod:(NSString *)method withPath:(NSString *)path target:(id)target selector:(SEL)selector; 41 | 42 | - (BOOL)supportsMethod:(NSString *)method; 43 | - (RouteResponse *)routeMethod:(NSString *)method withPath:(NSString *)path parameters:(NSDictionary *)params request:(HTTPMessage *)request connection:(HTTPConnection *)connection; 44 | 45 | @end 46 | --------------------------------------------------------------------------------