You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by sh...@apache.org on 2014/11/08 03:32:13 UTC

[45/50] [abbrv] cordova-plugins git commit: Moved files to local-webserver folder to prepare for the move to the cordova-plugins repo

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m
new file mode 100644
index 0000000..d4e3f39
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.m
@@ -0,0 +1,845 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#if !__has_feature(objc_arc)
+#error GCDWebServer requires ARC
+#endif
+
+#import <TargetConditionals.h>
+#import <netdb.h>
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+#import <libkern/OSAtomic.h>
+#endif
+
+#import "GCDWebServerPrivate.h"
+
+#define kHeadersReadCapacity (1 * 1024)
+#define kBodyReadCapacity (256 * 1024)
+
+typedef void (^ReadDataCompletionBlock)(BOOL success);
+typedef void (^ReadHeadersCompletionBlock)(NSData* extraData);
+typedef void (^ReadBodyCompletionBlock)(BOOL success);
+
+typedef void (^WriteDataCompletionBlock)(BOOL success);
+typedef void (^WriteHeadersCompletionBlock)(BOOL success);
+typedef void (^WriteBodyCompletionBlock)(BOOL success);
+
+static NSData* _CRLFData = nil;
+static NSData* _CRLFCRLFData = nil;
+static NSData* _continueData = nil;
+static NSData* _lastChunkData = nil;
+static NSString* _digestAuthenticationNonce = nil;
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+static int32_t _connectionCounter = 0;
+#endif
+
+@interface GCDWebServerConnection () {
+@private
+  GCDWebServer* _server;
+  NSData* _localAddress;
+  NSData* _remoteAddress;
+  CFSocketNativeHandle _socket;
+  NSUInteger _bytesRead;
+  NSUInteger _bytesWritten;
+  BOOL _virtualHEAD;
+  
+  CFHTTPMessageRef _requestMessage;
+  GCDWebServerRequest* _request;
+  GCDWebServerHandler* _handler;
+  CFHTTPMessageRef _responseMessage;
+  GCDWebServerResponse* _response;
+  NSInteger _statusCode;
+  
+  BOOL _opened;
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+  NSUInteger _connectionIndex;
+  NSString* _requestPath;
+  int _requestFD;
+  NSString* _responsePath;
+  int _responseFD;
+#endif
+}
+@end
+
+@implementation GCDWebServerConnection (Read)
+
+- (void)_readData:(NSMutableData*)data withLength:(NSUInteger)length completionBlock:(ReadDataCompletionBlock)block {
+  dispatch_read(_socket, length, kGCDWebServerGCDQueue, ^(dispatch_data_t buffer, int error) {
+    
+    @autoreleasepool {
+      if (error == 0) {
+        size_t size = dispatch_data_get_size(buffer);
+        if (size > 0) {
+          NSUInteger originalLength = data.length;
+          dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
+            [data appendBytes:chunkBytes length:chunkSize];
+            return true;
+          });
+          [self didReadBytes:((char*)data.bytes + originalLength) length:(data.length - originalLength)];
+          block(YES);
+        } else {
+          if (_bytesRead > 0) {
+            GWS_LOG_ERROR(@"No more data available on socket %i", _socket);
+          } else {
+            GWS_LOG_WARNING(@"No data received from socket %i", _socket);
+          }
+          block(NO);
+        }
+      } else {
+        GWS_LOG_ERROR(@"Error while reading from socket %i: %s (%i)", _socket, strerror(error), error);
+        block(NO);
+      }
+    }
+    
+  });
+}
+
+- (void)_readHeaders:(NSMutableData*)headersData withCompletionBlock:(ReadHeadersCompletionBlock)block {
+  GWS_DCHECK(_requestMessage);
+  [self _readData:headersData withLength:NSUIntegerMax completionBlock:^(BOOL success) {
+    
+    if (success) {
+      NSRange range = [headersData rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, headersData.length)];
+      if (range.location == NSNotFound) {
+        [self _readHeaders:headersData withCompletionBlock:block];
+      } else {
+        NSUInteger length = range.location + range.length;
+        if (CFHTTPMessageAppendBytes(_requestMessage, headersData.bytes, length)) {
+          if (CFHTTPMessageIsHeaderComplete(_requestMessage)) {
+            block([headersData subdataWithRange:NSMakeRange(length, headersData.length - length)]);
+          } else {
+            GWS_LOG_ERROR(@"Failed parsing request headers from socket %i", _socket);
+            block(nil);
+          }
+        } else {
+          GWS_LOG_ERROR(@"Failed appending request headers data from socket %i", _socket);
+          block(nil);
+        }
+      }
+    } else {
+      block(nil);
+    }
+    
+  }];
+}
+
+- (void)_readBodyWithRemainingLength:(NSUInteger)length completionBlock:(ReadBodyCompletionBlock)block {
+  GWS_DCHECK([_request hasBody] && ![_request usesChunkedTransferEncoding]);
+  NSMutableData* bodyData = [[NSMutableData alloc] initWithCapacity:kBodyReadCapacity];
+  [self _readData:bodyData withLength:length completionBlock:^(BOOL success) {
+    
+    if (success) {
+      if (bodyData.length <= length) {
+        NSError* error = nil;
+        if ([_request performWriteData:bodyData error:&error]) {
+          NSUInteger remainingLength = length - bodyData.length;
+          if (remainingLength) {
+            [self _readBodyWithRemainingLength:remainingLength completionBlock:block];
+          } else {
+            block(YES);
+          }
+        } else {
+          GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+          block(NO);
+        }
+      } else {
+        GWS_LOG_ERROR(@"Unexpected extra content reading request body on socket %i", _socket);
+        block(NO);
+        GWS_DNOT_REACHED();
+      }
+    } else {
+      block(NO);
+    }
+    
+  }];
+}
+
+static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
+  char buffer[size + 1];
+  bcopy(bytes, buffer, size);
+  buffer[size] = 0;
+  char* end = NULL;
+  long result = strtol(buffer, &end, 16);
+  return ((end != NULL) && (*end == 0) && (result >= 0) ? result : NSNotFound);
+}
+
+- (void)_readNextBodyChunk:(NSMutableData*)chunkData completionBlock:(ReadBodyCompletionBlock)block {
+  GWS_DCHECK([_request hasBody] && [_request usesChunkedTransferEncoding]);
+  
+  while (1) {
+    NSRange range = [chunkData rangeOfData:_CRLFData options:0 range:NSMakeRange(0, chunkData.length)];
+    if (range.location == NSNotFound) {
+      break;
+    }
+    NSRange extensionRange = [chunkData rangeOfData:[NSData dataWithBytes:";" length:1] options:0 range:NSMakeRange(0, range.location)];  // Ignore chunk extensions
+    NSUInteger length = _ScanHexNumber((char*)chunkData.bytes, extensionRange.location != NSNotFound ? extensionRange.location : range.location);
+    if (length != NSNotFound) {
+      if (length) {
+        if (chunkData.length < range.location + range.length + length + 2) {
+          break;
+        }
+        const char* ptr = (char*)chunkData.bytes + range.location + range.length + length;
+        if ((*ptr == '\r') && (*(ptr + 1) == '\n')) {
+          NSError* error = nil;
+          if ([_request performWriteData:[chunkData subdataWithRange:NSMakeRange(range.location + range.length, length)] error:&error]) {
+            [chunkData replaceBytesInRange:NSMakeRange(0, range.location + range.length + length + 2) withBytes:NULL length:0];
+          } else {
+            GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+            block(NO);
+            return;
+          }
+        } else {
+          GWS_LOG_ERROR(@"Missing terminating CRLF sequence for chunk reading request body on socket %i", _socket);
+          block(NO);
+          return;
+        }
+      } else {
+        NSRange trailerRange = [chunkData rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(range.location, chunkData.length - range.location)];  // Ignore trailers
+        if (trailerRange.location != NSNotFound) {
+          block(YES);
+          return;
+        }
+      }
+    } else {
+      GWS_LOG_ERROR(@"Invalid chunk length reading request body on socket %i", _socket);
+      block(NO);
+      return;
+    }
+  }
+  
+  [self _readData:chunkData withLength:NSUIntegerMax completionBlock:^(BOOL success) {
+    
+    if (success) {
+      [self _readNextBodyChunk:chunkData completionBlock:block];
+    } else {
+      block(NO);
+    }
+    
+  }];
+}
+
+@end
+
+@implementation GCDWebServerConnection (Write)
+
+- (void)_writeData:(NSData*)data withCompletionBlock:(WriteDataCompletionBlock)block {
+  dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, kGCDWebServerGCDQueue, ^{
+    [data self];  // Keeps ARC from releasing data too early
+  });
+  dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t remainingData, int error) {
+    
+    @autoreleasepool {
+      if (error == 0) {
+        GWS_DCHECK(remainingData == NULL);
+        [self didWriteBytes:data.bytes length:data.length];
+        block(YES);
+      } else {
+        GWS_LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
+        block(NO);
+      }
+    }
+    
+  });
+#if !OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+  dispatch_release(buffer);
+#endif
+}
+
+- (void)_writeHeadersWithCompletionBlock:(WriteHeadersCompletionBlock)block {
+  GWS_DCHECK(_responseMessage);
+  CFDataRef data = CFHTTPMessageCopySerializedMessage(_responseMessage);
+  [self _writeData:(__bridge NSData*)data withCompletionBlock:block];
+  CFRelease(data);
+}
+
+- (void)_writeBodyWithCompletionBlock:(WriteBodyCompletionBlock)block {
+  GWS_DCHECK([_response hasBody]);
+  [_response performReadDataWithCompletion:^(NSData* data, NSError* error) {
+    
+    if (data) {
+      if (data.length) {
+        if (_response.usesChunkedTransferEncoding) {
+          const char* hexString = [[NSString stringWithFormat:@"%lx", (unsigned long)data.length] UTF8String];
+          size_t hexLength = strlen(hexString);
+          NSData* chunk = [NSMutableData dataWithLength:(hexLength + 2 + data.length + 2)];
+          if (chunk == nil) {
+            GWS_LOG_ERROR(@"Failed allocating memory for response body chunk for socket %i: %@", _socket, error);
+            block(NO);
+            return;
+          }
+          char* ptr = (char*)[(NSMutableData*)chunk mutableBytes];
+          bcopy(hexString, ptr, hexLength);
+          ptr += hexLength;
+          *ptr++ = '\r';
+          *ptr++ = '\n';
+          bcopy(data.bytes, ptr, data.length);
+          ptr += data.length;
+          *ptr++ = '\r';
+          *ptr = '\n';
+          data = chunk;
+        }
+        [self _writeData:data withCompletionBlock:^(BOOL success) {
+          
+          if (success) {
+            [self _writeBodyWithCompletionBlock:block];
+          } else {
+            block(NO);
+          }
+          
+        }];
+      } else {
+        if (_response.usesChunkedTransferEncoding) {
+          [self _writeData:_lastChunkData withCompletionBlock:^(BOOL success) {
+            
+            block(success);
+            
+          }];
+        } else {
+          block(YES);
+        }
+      }
+    } else {
+      GWS_LOG_ERROR(@"Failed reading response body for socket %i: %@", _socket, error);
+      block(NO);
+    }
+    
+  }];
+}
+
+@end
+
+@implementation GCDWebServerConnection
+
+@synthesize server=_server, localAddressData=_localAddress, remoteAddressData=_remoteAddress, totalBytesRead=_bytesRead, totalBytesWritten=_bytesWritten;
+
++ (void)initialize {
+  if (_CRLFData == nil) {
+    _CRLFData = [[NSData alloc] initWithBytes:"\r\n" length:2];
+    GWS_DCHECK(_CRLFData);
+  }
+  if (_CRLFCRLFData == nil) {
+    _CRLFCRLFData = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
+    GWS_DCHECK(_CRLFCRLFData);
+  }
+  if (_continueData == nil) {
+    CFHTTPMessageRef message = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 100, NULL, kCFHTTPVersion1_1);
+    _continueData = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(message));
+    CFRelease(message);
+    GWS_DCHECK(_continueData);
+  }
+  if (_lastChunkData == nil) {
+    _lastChunkData = [[NSData alloc] initWithBytes:"0\r\n\r\n" length:5];
+  }
+  if (_digestAuthenticationNonce == nil) {
+    CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
+    _digestAuthenticationNonce = GCDWebServerComputeMD5Digest(@"%@", CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)));
+    CFRelease(uuid);
+  }
+}
+
+- (BOOL)isUsingIPv6 {
+  const struct sockaddr* localSockAddr = _localAddress.bytes;
+  return (localSockAddr->sa_family == AF_INET6);
+}
+
+- (void)_initializeResponseHeadersWithStatusCode:(NSInteger)statusCode {
+  _statusCode = statusCode;
+  _responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
+  CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
+  CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (__bridge CFStringRef)_server.serverName);
+  CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (__bridge CFStringRef)GCDWebServerFormatRFC822([NSDate date]));
+}
+
+- (void)_startProcessingRequest {
+  GWS_DCHECK(_responseMessage == NULL);
+  
+  GCDWebServerResponse* preflightResponse = [self preflightRequest:_request];
+  if (preflightResponse) {
+    [self _finishProcessingRequest:preflightResponse];
+  } else {
+    [self processRequest:_request completion:^(GCDWebServerResponse* processResponse) {
+      [self _finishProcessingRequest:processResponse];
+    }];
+  }
+}
+
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+- (void)_finishProcessingRequest:(GCDWebServerResponse*)response {
+  GWS_DCHECK(_responseMessage == NULL);
+  BOOL hasBody = NO;
+  
+  if (response) {
+    response = [self overrideResponse:response forRequest:_request];
+  }
+  if (response) {
+    if ([response hasBody]) {
+      [response prepareForReading];
+      hasBody = !_virtualHEAD;
+    }
+    NSError* error = nil;
+    if (hasBody && ![response performOpen:&error]) {
+      GWS_LOG_ERROR(@"Failed opening response body for socket %i: %@", _socket, error);
+    } else {
+      _response = response;
+    }
+  }
+  
+  if (_response) {
+    [self _initializeResponseHeadersWithStatusCode:_response.statusCode];
+    if (_response.lastModifiedDate) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (__bridge CFStringRef)GCDWebServerFormatRFC822(_response.lastModifiedDate));
+    }
+    if (_response.eTag) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (__bridge CFStringRef)_response.eTag);
+    }
+    if ((_response.statusCode >= 200) && (_response.statusCode < 300)) {
+      if (_response.cacheControlMaxAge > 0) {
+        CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), (__bridge CFStringRef)[NSString stringWithFormat:@"max-age=%i, public", (int)_response.cacheControlMaxAge]);
+      } else {
+        CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Cache-Control"), CFSTR("no-cache"));
+      }
+    }
+    if (_response.contentType != nil) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Type"), (__bridge CFStringRef)GCDWebServerNormalizeHeaderValue(_response.contentType));
+    }
+    if (_response.contentLength != NSUIntegerMax) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Content-Length"), (__bridge CFStringRef)[NSString stringWithFormat:@"%lu", (unsigned long)_response.contentLength]);
+    }
+    if (_response.usesChunkedTransferEncoding) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Transfer-Encoding"), CFSTR("chunked"));
+    }
+    [_response.additionalHeaders enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL* stop) {
+      CFHTTPMessageSetHeaderFieldValue(_responseMessage, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
+    }];
+    [self _writeHeadersWithCompletionBlock:^(BOOL success) {
+      
+      if (success) {
+        if (hasBody) {
+          [self _writeBodyWithCompletionBlock:^(BOOL successInner) {
+            
+            [_response performClose];  // TODO: There's nothing we can do on failure as headers have already been sent
+            
+          }];
+        }
+      } else if (hasBody) {
+        [_response performClose];
+      }
+      
+    }];
+  } else {
+    [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+  }
+  
+}
+
+- (void)_readBodyWithLength:(NSUInteger)length initialData:(NSData*)initialData {
+  NSError* error = nil;
+  if (![_request performOpen:&error]) {
+    GWS_LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
+    [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+    return;
+  }
+  
+  if (initialData.length) {
+    if (![_request performWriteData:initialData error:&error]) {
+      GWS_LOG_ERROR(@"Failed writing request body on socket %i: %@", _socket, error);
+      if (![_request performClose:&error]) {
+        GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+      }
+      [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+      return;
+    }
+    length -= initialData.length;
+  }
+  
+  if (length) {
+    [self _readBodyWithRemainingLength:length completionBlock:^(BOOL success) {
+      
+      NSError* localError = nil;
+      if ([_request performClose:&localError]) {
+        [self _startProcessingRequest];
+      } else {
+        GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+        [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+      }
+      
+    }];
+  } else {
+    if ([_request performClose:&error]) {
+      [self _startProcessingRequest];
+    } else {
+      GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+      [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+    }
+  }
+}
+
+- (void)_readChunkedBodyWithInitialData:(NSData*)initialData {
+  NSError* error = nil;
+  if (![_request performOpen:&error]) {
+    GWS_LOG_ERROR(@"Failed opening request body for socket %i: %@", _socket, error);
+    [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+    return;
+  }
+  
+  NSMutableData* chunkData = [[NSMutableData alloc] initWithData:initialData];
+  [self _readNextBodyChunk:chunkData completionBlock:^(BOOL success) {
+  
+    NSError* localError = nil;
+    if ([_request performClose:&localError]) {
+      [self _startProcessingRequest];
+    } else {
+      GWS_LOG_ERROR(@"Failed closing request body for socket %i: %@", _socket, error);
+      [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+    }
+    
+  }];
+}
+
+- (void)_readRequestHeaders {
+  _requestMessage = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, true);
+  NSMutableData* headersData = [[NSMutableData alloc] initWithCapacity:kHeadersReadCapacity];
+  [self _readHeaders:headersData withCompletionBlock:^(NSData* extraData) {
+    
+    if (extraData) {
+      NSString* requestMethod = CFBridgingRelease(CFHTTPMessageCopyRequestMethod(_requestMessage));  // Method verbs are case-sensitive and uppercase
+      if (_server.shouldAutomaticallyMapHEADToGET && [requestMethod isEqualToString:@"HEAD"]) {
+        requestMethod = @"GET";
+        _virtualHEAD = YES;
+      }
+      NSDictionary* requestHeaders = CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_requestMessage));  // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones
+      NSURL* requestURL = CFBridgingRelease(CFHTTPMessageCopyRequestURL(_requestMessage));
+      if (requestURL) {
+        requestURL = [self rewriteRequestURL:requestURL withMethod:requestMethod headers:requestHeaders];
+        GWS_DCHECK(requestURL);
+      }
+      NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(CFBridgingRelease(CFURLCopyPath((CFURLRef)requestURL))) : nil;  // Don't use -[NSURL path] which strips the ending slash
+      NSString* queryString = requestURL ? CFBridgingRelease(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil;  // Don't use -[NSURL query] to make sure query is not unescaped;
+      NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{};
+      if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) {
+        for (_handler in _server.handlers) {
+          _request = _handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery);
+          if (_request) {
+            break;
+          }
+        }
+        if (_request) {
+          if ([_request hasBody]) {
+            [_request prepareForWriting];
+            if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
+              NSString* expectHeader = [requestHeaders objectForKey:@"Expect"];
+              if (expectHeader) {
+                if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) {  // TODO: Actually validate request before continuing
+                  [self _writeData:_continueData withCompletionBlock:^(BOOL success) {
+                    
+                    if (success) {
+                      if (_request.usesChunkedTransferEncoding) {
+                        [self _readChunkedBodyWithInitialData:extraData];
+                      } else {
+                        [self _readBodyWithLength:_request.contentLength initialData:extraData];
+                      }
+                    }
+                    
+                  }];
+                } else {
+                  GWS_LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket);
+                  [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed];
+                }
+              } else {
+                if (_request.usesChunkedTransferEncoding) {
+                  [self _readChunkedBodyWithInitialData:extraData];
+                } else {
+                  [self _readBodyWithLength:_request.contentLength initialData:extraData];
+                }
+              }
+            } else {
+              GWS_LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket);
+              [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest];
+            }
+          } else {
+            [self _startProcessingRequest];
+          }
+        } else {
+          _request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery];
+          GWS_DCHECK(_request);
+          [self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed];
+        }
+      } else {
+        [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+        GWS_DNOT_REACHED();
+      }
+    } else {
+      [self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
+    }
+    
+  }];
+}
+
+- (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket {
+  if ((self = [super init])) {
+    _server = server;
+    _localAddress = localAddress;
+    _remoteAddress = remoteAddress;
+    _socket = socket;
+    GWS_LOG_DEBUG(@"Did open connection on socket %i", _socket);
+    
+    [_server willStartConnection:self];
+    
+    if (![self open]) {
+      close(_socket);
+      return nil;
+    }
+    _opened = YES;
+    
+    [self _readRequestHeaders];
+  }
+  return self;
+}
+
+- (NSString*)localAddressString {
+  return GCDWebServerStringFromSockAddr(_localAddress.bytes, YES);
+}
+
+- (NSString*)remoteAddressString {
+  return GCDWebServerStringFromSockAddr(_remoteAddress.bytes, YES);
+}
+
+- (void)dealloc {
+  int result = close(_socket);
+  if (result != 0) {
+    GWS_LOG_ERROR(@"Failed closing socket %i for connection: %s (%i)", _socket, strerror(errno), errno);
+  } else {
+    GWS_LOG_DEBUG(@"Did close connection on socket %i", _socket);
+  }
+  
+  if (_opened) {
+    [self close];
+  }
+  
+  [_server didEndConnection:self];
+  
+  if (_requestMessage) {
+    CFRelease(_requestMessage);
+  }
+  
+  if (_responseMessage) {
+    CFRelease(_responseMessage);
+  }
+}
+
+@end
+
+@implementation GCDWebServerConnection (Subclassing)
+
+- (BOOL)open {
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+  if (_server.recordingEnabled) {
+    _connectionIndex = OSAtomicIncrement32(&_connectionCounter);
+    
+    _requestPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
+    _requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    GWS_DCHECK(_requestFD > 0);
+    
+    _responsePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
+    _responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+    GWS_DCHECK(_responseFD > 0);
+  }
+#endif
+  
+  return YES;
+}
+
+- (void)didReadBytes:(const void*)bytes length:(NSUInteger)length {
+  GWS_LOG_DEBUG(@"Connection received %lu bytes on socket %i", (unsigned long)length, _socket);
+  _bytesRead += length;
+  
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+  if ((_requestFD > 0) && (write(_requestFD, bytes, length) != (ssize_t)length)) {
+    GWS_LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno);
+    close(_requestFD);
+    _requestFD = 0;
+  }
+#endif
+}
+
+- (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length {
+  GWS_LOG_DEBUG(@"Connection sent %lu bytes on socket %i", (unsigned long)length, _socket);
+  _bytesWritten += length;
+  
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+  if ((_responseFD > 0) && (write(_responseFD, bytes, length) != (ssize_t)length)) {
+    GWS_LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno);
+    close(_responseFD);
+    _responseFD = 0;
+  }
+#endif
+}
+
+- (NSURL*)rewriteRequestURL:(NSURL*)url withMethod:(NSString*)method headers:(NSDictionary*)headers {
+  return url;
+}
+
+// https://tools.ietf.org/html/rfc2617
+- (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request {
+  GWS_LOG_DEBUG(@"Connection on socket %i preflighting request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
+  GCDWebServerResponse* response = nil;
+  if (_server.authenticationBasicAccounts) {
+    __block BOOL authenticated = NO;
+    NSString* authorizationHeader = [request.headers objectForKey:@"Authorization"];
+    if ([authorizationHeader hasPrefix:@"Basic "]) {
+      NSString* basicAccount = [authorizationHeader substringFromIndex:6];
+      [_server.authenticationBasicAccounts enumerateKeysAndObjectsUsingBlock:^(NSString* username, NSString* digest, BOOL* stop) {
+        if ([basicAccount isEqualToString:digest]) {
+          authenticated = YES;
+          *stop = YES;
+        }
+      }];
+    }
+    if (!authenticated) {
+      response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_Unauthorized];
+      [response setValue:[NSString stringWithFormat:@"Basic realm=\"%@\"", _server.authenticationRealm] forAdditionalHeader:@"WWW-Authenticate"];
+    }
+  } else if (_server.authenticationDigestAccounts) {
+    BOOL authenticated = NO;
+    BOOL isStaled = NO;
+    NSString* authorizationHeader = [request.headers objectForKey:@"Authorization"];
+    if ([authorizationHeader hasPrefix:@"Digest "]) {
+      NSString* realm = GCDWebServerExtractHeaderValueParameter(authorizationHeader, @"realm");
+      if ([realm isEqualToString:_server.authenticationRealm]) {
+        NSString* nonce = GCDWebServerExtractHeaderValueParameter(authorizationHeader, @"nonce");
+        if ([nonce isEqualToString:_digestAuthenticationNonce]) {
+          NSString* username = GCDWebServerExtractHeaderValueParameter(authorizationHeader, @"username");
+          NSString* uri = GCDWebServerExtractHeaderValueParameter(authorizationHeader, @"uri");
+          NSString* actualResponse = GCDWebServerExtractHeaderValueParameter(authorizationHeader, @"response");
+          NSString* ha1 = [_server.authenticationDigestAccounts objectForKey:username];
+          NSString* ha2 = GCDWebServerComputeMD5Digest(@"%@:%@", request.method, uri);  // We cannot use "request.path" as the query string is required
+          NSString* expectedResponse = GCDWebServerComputeMD5Digest(@"%@:%@:%@", ha1, _digestAuthenticationNonce, ha2);
+          if ([actualResponse isEqualToString:expectedResponse]) {
+            authenticated = YES;
+          }
+        } else if (nonce.length) {
+          isStaled = YES;
+        }
+      }
+    }
+    if (!authenticated) {
+      response = [GCDWebServerResponse responseWithStatusCode:kGCDWebServerHTTPStatusCode_Unauthorized];
+      [response setValue:[NSString stringWithFormat:@"Digest realm=\"%@\", nonce=\"%@\"%@", _server.authenticationRealm, _digestAuthenticationNonce, isStaled ? @", stale=TRUE" : @""] forAdditionalHeader:@"WWW-Authenticate"];  // TODO: Support Quality of Protection ("qop")
+    }
+  }
+  return response;
+}
+
+- (void)processRequest:(GCDWebServerRequest*)request completion:(GCDWebServerCompletionBlock)completion {
+  GWS_LOG_DEBUG(@"Connection on socket %i processing request \"%@ %@\" with %lu bytes body", _socket, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead);
+  @try {
+    _handler.asyncProcessBlock(request, completion);
+  }
+  @catch (NSException* exception) {
+    GWS_LOG_EXCEPTION(exception);
+  }
+}
+
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26
+static inline BOOL _CompareResources(NSString* responseETag, NSString* requestETag, NSDate* responseLastModified, NSDate* requestLastModified) {
+  if ([requestETag isEqualToString:@"*"] && (!responseLastModified || !requestLastModified || ([responseLastModified compare:requestLastModified] != NSOrderedDescending))) {
+    return YES;
+  } else {
+    if ([responseETag isEqualToString:requestETag]) {
+      return YES;
+    }
+    if (responseLastModified && requestLastModified && ([responseLastModified compare:requestLastModified] != NSOrderedDescending)) {
+      return YES;
+    }
+  }
+  return NO;
+}
+
+- (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request {
+  if ((response.statusCode >= 200) && (response.statusCode < 300) && _CompareResources(response.eTag, request.ifNoneMatch, response.lastModifiedDate, request.ifModifiedSince)) {
+    NSInteger code = [request.method isEqualToString:@"HEAD"] || [request.method isEqualToString:@"GET"] ? kGCDWebServerHTTPStatusCode_NotModified : kGCDWebServerHTTPStatusCode_PreconditionFailed;
+    GCDWebServerResponse* newResponse = [GCDWebServerResponse responseWithStatusCode:code];
+    newResponse.cacheControlMaxAge = response.cacheControlMaxAge;
+    newResponse.lastModifiedDate = response.lastModifiedDate;
+    newResponse.eTag = response.eTag;
+    GWS_DCHECK(newResponse);
+    return newResponse;
+  }
+  return response;
+}
+
+- (void)abortRequest:(GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode {
+  GWS_DCHECK(_responseMessage == NULL);
+  GWS_DCHECK((statusCode >= 400) && (statusCode < 600));
+  [self _initializeResponseHeadersWithStatusCode:statusCode];
+  [self _writeHeadersWithCompletionBlock:^(BOOL success) {
+    ;  // Nothing more to do
+  }];
+  GWS_LOG_DEBUG(@"Connection aborted with status code %i on socket %i", (int)statusCode, _socket);
+}
+
+- (void)close {
+#ifdef __GCDWEBSERVER_ENABLE_TESTING__
+  if (_requestPath) {
+    BOOL success = NO;
+    NSError* error = nil;
+    if (_requestFD > 0) {
+      close(_requestFD);
+      NSString* name = [NSString stringWithFormat:@"%03lu-%@.request", (unsigned long)_connectionIndex, _virtualHEAD ? @"HEAD" : _request.method];
+      success = [[NSFileManager defaultManager] moveItemAtPath:_requestPath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
+    }
+    if (!success) {
+      GWS_LOG_ERROR(@"Failed saving recorded request: %@", error);
+      GWS_DNOT_REACHED();
+    }
+    unlink([_requestPath fileSystemRepresentation]);
+  }
+  
+  if (_responsePath) {
+    BOOL success = NO;
+    NSError* error = nil;
+    if (_responseFD > 0) {
+      close(_responseFD);
+      NSString* name = [NSString stringWithFormat:@"%03lu-%i.response", (unsigned long)_connectionIndex, (int)_statusCode];
+      success = [[NSFileManager defaultManager] moveItemAtPath:_responsePath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
+    }
+    if (!success) {
+      GWS_LOG_ERROR(@"Failed saving recorded response: %@", error);
+      GWS_DNOT_REACHED();
+    }
+    unlink([_responsePath fileSystemRepresentation]);
+  }
+#endif
+  
+  if (_request) {
+    GWS_LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
+  } else {
+    GWS_LOG_VERBOSE(@"[%@] %@ %i \"(invalid request)\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
+  }
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h
new file mode 100644
index 0000000..a8b2857
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h
@@ -0,0 +1,101 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *  Converts a file extension to the corresponding MIME type.
+ *  If there is no match, "application/octet-stream" is returned.
+ */
+NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension);
+
+/**
+ *  Add percent-escapes to a string so it can be used in a URL.
+ *  The legal characters ":@/?&=+" are also escaped to ensure compatibility
+ *  with URL encoded forms and URL queries.
+ */
+NSString* GCDWebServerEscapeURLString(NSString* string);
+
+/**
+ *  Unescapes a URL percent-encoded string.
+ */
+NSString* GCDWebServerUnescapeURLString(NSString* string);
+
+/**
+ *  Extracts the unescaped names and values from an
+ *  "application/x-www-form-urlencoded" form.
+ *  http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
+ */
+NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
+
+/**
+ *  On OS X, returns the IPv4 or IPv6 address as a string of the primary
+ *  connected service or nil if not available.
+ *  
+ *  On iOS, returns the IPv4 or IPv6 address as a string of the WiFi
+ *  interface if connected or nil otherwise.
+ */
+NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6);
+
+/**
+ *  Converts a date into a string using RFC822 formatting.
+ *  https://tools.ietf.org/html/rfc822#section-5
+ *  https://tools.ietf.org/html/rfc1123#section-5.2.14
+ */
+NSString* GCDWebServerFormatRFC822(NSDate* date);
+
+/**
+ *  Converts a RFC822 formatted string into a date.
+ *  https://tools.ietf.org/html/rfc822#section-5
+ *  https://tools.ietf.org/html/rfc1123#section-5.2.14
+ *
+ *  @warning Timezones other than GMT are not supported by this function.
+ */
+NSDate* GCDWebServerParseRFC822(NSString* string);
+
+/**
+ *  Converts a date into a string using IOS 8601 formatting.
+ *  http://tools.ietf.org/html/rfc3339#section-5.6
+ */
+NSString* GCDWebServerFormatISO8601(NSDate* date);
+
+/**
+ *  Converts a ISO 8601 formatted string into a date.
+ *  http://tools.ietf.org/html/rfc3339#section-5.6
+ *
+ *  @warning Only "calendar" variant is supported at this time and timezones
+ *  other than GMT are not supported either.
+ */
+NSDate* GCDWebServerParseISO8601(NSString* string);
+
+#ifdef __cplusplus
+}
+#endif

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m
new file mode 100644
index 0000000..d81af0b
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m
@@ -0,0 +1,299 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#if !__has_feature(objc_arc)
+#error GCDWebServer requires ARC
+#endif
+
+#import <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#import <MobileCoreServices/MobileCoreServices.h>
+#else
+#import <SystemConfiguration/SystemConfiguration.h>
+#endif
+#import <CommonCrypto/CommonDigest.h>
+
+#import <ifaddrs.h>
+#import <net/if.h>
+#import <netdb.h>
+
+#import "GCDWebServerPrivate.h"
+
+static NSDateFormatter* _dateFormatterRFC822 = nil;
+static NSDateFormatter* _dateFormatterISO8601 = nil;
+static dispatch_queue_t _dateFormatterQueue = NULL;
+
+// TODO: Handle RFC 850 and ANSI C's asctime() format
+void GCDWebServerInitializeFunctions() {
+  GWS_DCHECK([NSThread isMainThread]);  // NSDateFormatter should be initialized on main thread
+  if (_dateFormatterRFC822 == nil) {
+    _dateFormatterRFC822 = [[NSDateFormatter alloc] init];
+    _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
+    _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
+    _dateFormatterRFC822.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
+    GWS_DCHECK(_dateFormatterRFC822);
+  }
+  if (_dateFormatterISO8601 == nil) {
+    _dateFormatterISO8601 = [[NSDateFormatter alloc] init];
+    _dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
+    _dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
+    _dateFormatterISO8601.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
+    GWS_DCHECK(_dateFormatterISO8601);
+  }
+  if (_dateFormatterQueue == NULL) {
+    _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+    GWS_DCHECK(_dateFormatterQueue);
+  }
+}
+
+NSString* GCDWebServerNormalizeHeaderValue(NSString* value) {
+  if (value) {
+    NSRange range = [value rangeOfString:@";"];  // Assume part before ";" separator is case-insensitive
+    if (range.location != NSNotFound) {
+      value = [[[value substringToIndex:range.location] lowercaseString] stringByAppendingString:[value substringFromIndex:range.location]];
+    } else {
+      value = [value lowercaseString];
+    }
+  }
+  return value;
+}
+
+NSString* GCDWebServerTruncateHeaderValue(NSString* value) {
+  NSRange range = [value rangeOfString:@";"];
+  return range.location != NSNotFound ? [value substringToIndex:range.location] : value;
+}
+
+NSString* GCDWebServerExtractHeaderValueParameter(NSString* value, NSString* name) {
+  NSString* parameter = nil;
+  NSScanner* scanner = [[NSScanner alloc] initWithString:value];
+  [scanner setCaseSensitive:NO];  // Assume parameter names are case-insensitive
+  NSString* string = [NSString stringWithFormat:@"%@=", name];
+  if ([scanner scanUpToString:string intoString:NULL]) {
+    [scanner scanString:string intoString:NULL];
+    if ([scanner scanString:@"\"" intoString:NULL]) {
+      [scanner scanUpToString:@"\"" intoString:&parameter];
+    } else {
+      [scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:&parameter];
+    }
+  }
+  return parameter;
+}
+
+// http://www.w3schools.com/tags/ref_charactersets.asp
+NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
+  NSStringEncoding encoding = kCFStringEncodingInvalidId;
+  if (charset) {
+    encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset));
+  }
+  return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
+}
+
+NSString* GCDWebServerFormatRFC822(NSDate* date) {
+  __block NSString* string;
+  dispatch_sync(_dateFormatterQueue, ^{
+    string = [_dateFormatterRFC822 stringFromDate:date];
+  });
+  return string;
+}
+
+NSDate* GCDWebServerParseRFC822(NSString* string) {
+  __block NSDate* date;
+  dispatch_sync(_dateFormatterQueue, ^{
+    date = [_dateFormatterRFC822 dateFromString:string];
+  });
+  return date;
+}
+
+NSString* GCDWebServerFormatISO8601(NSDate* date) {
+  __block NSString* string;
+  dispatch_sync(_dateFormatterQueue, ^{
+    string = [_dateFormatterISO8601 stringFromDate:date];
+  });
+  return string;
+}
+
+NSDate* GCDWebServerParseISO8601(NSString* string) {
+  __block NSDate* date;
+  dispatch_sync(_dateFormatterQueue, ^{
+    date = [_dateFormatterISO8601 dateFromString:string];
+  });
+  return date;
+}
+
+BOOL GCDWebServerIsTextContentType(NSString* type) {
+  return ([type hasPrefix:@"text/"] || [type hasPrefix:@"application/json"] || [type hasPrefix:@"application/xml"]);
+}
+
+NSString* GCDWebServerDescribeData(NSData* data, NSString* type) {
+  if (GCDWebServerIsTextContentType(type)) {
+    NSString* charset = GCDWebServerExtractHeaderValueParameter(type, @"charset");
+    NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
+    if (string) {
+      return string;
+    }
+  }
+  return [NSString stringWithFormat:@"<%lu bytes>", (unsigned long)data.length];
+}
+
+NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
+  static NSDictionary* _overrides = nil;
+  if (_overrides == nil) {
+    _overrides = [[NSDictionary alloc] initWithObjectsAndKeys:
+                  @"text/css", @"css",
+                  nil];
+  }
+  NSString* mimeType = nil;
+  extension = [extension lowercaseString];
+  if (extension.length) {
+    mimeType = [_overrides objectForKey:extension];
+    if (mimeType == nil) {
+      CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
+      if (uti) {
+        mimeType = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
+        CFRelease(uti);
+      }
+    }
+  }
+  return mimeType ? mimeType : kGCDWebServerDefaultMimeType;
+}
+
+NSString* GCDWebServerEscapeURLString(NSString* string) {
+  return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
+}
+
+NSString* GCDWebServerUnescapeURLString(NSString* string) {
+  return CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
+}
+
+NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
+  NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
+  NSScanner* scanner = [[NSScanner alloc] initWithString:form];
+  [scanner setCharactersToBeSkipped:nil];
+  while (1) {
+    NSString* key = nil;
+    if (![scanner scanUpToString:@"=" intoString:&key] || [scanner isAtEnd]) {
+      break;
+    }
+    [scanner setScanLocation:([scanner scanLocation] + 1)];
+    
+    NSString* value = nil;
+    [scanner scanUpToString:@"&" intoString:&value];
+    if (value == nil) {
+      value = @"";
+    }
+    
+    key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "];
+    NSString* unescapedKey = key ? GCDWebServerUnescapeURLString(key) : nil;
+    value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
+    NSString* unescapedValue = value ? GCDWebServerUnescapeURLString(value) : nil;
+    if (unescapedKey && unescapedValue) {
+      [parameters setObject:unescapedValue forKey:unescapedKey];
+    } else {
+      GWS_LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value);
+      GWS_DNOT_REACHED();
+    }
+    
+    if ([scanner isAtEnd]) {
+      break;
+    }
+    [scanner setScanLocation:([scanner scanLocation] + 1)];
+  }
+  return parameters;
+}
+
+NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL includeService) {
+  NSString* string = nil;
+  char hostBuffer[NI_MAXHOST];
+  char serviceBuffer[NI_MAXSERV];
+  if (getnameinfo(addr, addr->sa_len, hostBuffer, sizeof(hostBuffer), serviceBuffer, sizeof(serviceBuffer), NI_NUMERICHOST | NI_NUMERICSERV | NI_NOFQDN) >= 0) {
+    string = includeService ? [NSString stringWithFormat:@"%s:%s", hostBuffer, serviceBuffer] : [NSString stringWithUTF8String:hostBuffer];
+  } else {
+    GWS_DNOT_REACHED();
+  }
+  return string;
+}
+
+NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
+  NSString* address = nil;
+#if TARGET_OS_IPHONE
+#if !TARGET_IPHONE_SIMULATOR
+  const char* primaryInterface = "en0";  // WiFi interface on iOS
+#endif
+#else
+  const char* primaryInterface = NULL;
+  SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("GCDWebServer"), NULL, NULL);
+  if (store) {
+    CFPropertyListRef info = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4"));  // There is no equivalent for IPv6 but the primary interface should be the same
+    if (info) {
+      primaryInterface = [[NSString stringWithString:[(__bridge NSDictionary*)info objectForKey:@"PrimaryInterface"]] UTF8String];
+      CFRelease(info);
+    }
+    CFRelease(store);
+  }
+  if (primaryInterface == NULL) {
+    primaryInterface = "lo0";
+  }
+#endif
+  struct ifaddrs* list;
+  if (getifaddrs(&list) >= 0) {
+    for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) {
+#if TARGET_IPHONE_SIMULATOR
+      if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1"))  // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
+#else
+      if (strcmp(ifap->ifa_name, primaryInterface))
+#endif
+      {
+        continue;
+      }
+      if ((ifap->ifa_flags & IFF_UP) && ((!useIPv6 && (ifap->ifa_addr->sa_family == AF_INET)) || (useIPv6 && (ifap->ifa_addr->sa_family == AF_INET6)))) {
+        address = GCDWebServerStringFromSockAddr(ifap->ifa_addr, NO);
+        break;
+      }
+    }
+    freeifaddrs(list);
+  }
+  return address;
+}
+
+NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) {
+  va_list arguments;
+  va_start(arguments, format);
+  const char* string = [[[NSString alloc] initWithFormat:format arguments:arguments] UTF8String];
+  va_end(arguments);
+  unsigned char md5[CC_MD5_DIGEST_LENGTH];
+  CC_MD5(string, (CC_LONG)strlen(string), md5);
+  char buffer[2 * CC_MD5_DIGEST_LENGTH + 1];
+  for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
+    unsigned char byte = md5[i];
+    unsigned char byteHi = (byte & 0xF0) >> 4;
+    buffer[2 * i + 0] = byteHi >= 10 ? 'a' + byteHi - 10 : '0' + byteHi;
+    unsigned char byteLo = byte & 0x0F;
+    buffer[2 * i + 1] = byteLo >= 10 ? 'a' + byteLo - 10 : '0' + byteLo;
+  }
+  buffer[2 * CC_MD5_DIGEST_LENGTH] = 0;
+  return [NSString stringWithUTF8String:buffer];
+}

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
new file mode 100644
index 0000000..7af51a2
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
@@ -0,0 +1,116 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
+// http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
+
+#import <Foundation/Foundation.h>
+
+/**
+ *  Convenience constants for "informational" HTTP status codes.
+ */
+typedef NS_ENUM(NSInteger, GCDWebServerInformationalHTTPStatusCode) {
+  kGCDWebServerHTTPStatusCode_Continue = 100,
+  kGCDWebServerHTTPStatusCode_SwitchingProtocols = 101,
+  kGCDWebServerHTTPStatusCode_Processing = 102
+};
+
+/**
+ *  Convenience constants for "successful" HTTP status codes.
+ */
+typedef NS_ENUM(NSInteger, GCDWebServerSuccessfulHTTPStatusCode) {
+  kGCDWebServerHTTPStatusCode_OK = 200,
+  kGCDWebServerHTTPStatusCode_Created = 201,
+  kGCDWebServerHTTPStatusCode_Accepted = 202,
+  kGCDWebServerHTTPStatusCode_NonAuthoritativeInformation = 203,
+  kGCDWebServerHTTPStatusCode_NoContent = 204,
+  kGCDWebServerHTTPStatusCode_ResetContent = 205,
+  kGCDWebServerHTTPStatusCode_PartialContent = 206,
+  kGCDWebServerHTTPStatusCode_MultiStatus = 207,
+  kGCDWebServerHTTPStatusCode_AlreadyReported = 208
+};
+
+/**
+ *  Convenience constants for "redirection" HTTP status codes.
+ */
+typedef NS_ENUM(NSInteger, GCDWebServerRedirectionHTTPStatusCode) {
+  kGCDWebServerHTTPStatusCode_MultipleChoices = 300,
+  kGCDWebServerHTTPStatusCode_MovedPermanently = 301,
+  kGCDWebServerHTTPStatusCode_Found = 302,
+  kGCDWebServerHTTPStatusCode_SeeOther = 303,
+  kGCDWebServerHTTPStatusCode_NotModified = 304,
+  kGCDWebServerHTTPStatusCode_UseProxy = 305,
+  kGCDWebServerHTTPStatusCode_TemporaryRedirect = 307,
+  kGCDWebServerHTTPStatusCode_PermanentRedirect = 308
+};
+
+/**
+ *  Convenience constants for "client error" HTTP status codes.
+ */
+typedef NS_ENUM(NSInteger, GCDWebServerClientErrorHTTPStatusCode) {
+  kGCDWebServerHTTPStatusCode_BadRequest = 400,
+  kGCDWebServerHTTPStatusCode_Unauthorized = 401,
+  kGCDWebServerHTTPStatusCode_PaymentRequired = 402,
+  kGCDWebServerHTTPStatusCode_Forbidden = 403,
+  kGCDWebServerHTTPStatusCode_NotFound = 404,
+  kGCDWebServerHTTPStatusCode_MethodNotAllowed = 405,
+  kGCDWebServerHTTPStatusCode_NotAcceptable = 406,
+  kGCDWebServerHTTPStatusCode_ProxyAuthenticationRequired = 407,
+  kGCDWebServerHTTPStatusCode_RequestTimeout = 408,
+  kGCDWebServerHTTPStatusCode_Conflict = 409,
+  kGCDWebServerHTTPStatusCode_Gone = 410,
+  kGCDWebServerHTTPStatusCode_LengthRequired = 411,
+  kGCDWebServerHTTPStatusCode_PreconditionFailed = 412,
+  kGCDWebServerHTTPStatusCode_RequestEntityTooLarge = 413,
+  kGCDWebServerHTTPStatusCode_RequestURITooLong = 414,
+  kGCDWebServerHTTPStatusCode_UnsupportedMediaType = 415,
+  kGCDWebServerHTTPStatusCode_RequestedRangeNotSatisfiable = 416,
+  kGCDWebServerHTTPStatusCode_ExpectationFailed = 417,
+  kGCDWebServerHTTPStatusCode_UnprocessableEntity = 422,
+  kGCDWebServerHTTPStatusCode_Locked = 423,
+  kGCDWebServerHTTPStatusCode_FailedDependency = 424,
+  kGCDWebServerHTTPStatusCode_UpgradeRequired = 426,
+  kGCDWebServerHTTPStatusCode_PreconditionRequired = 428,
+  kGCDWebServerHTTPStatusCode_TooManyRequests = 429,
+  kGCDWebServerHTTPStatusCode_RequestHeaderFieldsTooLarge = 431
+};
+
+/**
+ *  Convenience constants for "server error" HTTP status codes.
+ */
+typedef NS_ENUM(NSInteger, GCDWebServerServerErrorHTTPStatusCode) {
+  kGCDWebServerHTTPStatusCode_InternalServerError = 500,
+  kGCDWebServerHTTPStatusCode_NotImplemented = 501,
+  kGCDWebServerHTTPStatusCode_BadGateway = 502,
+  kGCDWebServerHTTPStatusCode_ServiceUnavailable = 503,
+  kGCDWebServerHTTPStatusCode_GatewayTimeout = 504,
+  kGCDWebServerHTTPStatusCode_HTTPVersionNotSupported = 505,
+  kGCDWebServerHTTPStatusCode_InsufficientStorage = 507,
+  kGCDWebServerHTTPStatusCode_LoopDetected = 508,
+  kGCDWebServerHTTPStatusCode_NotExtended = 510,
+  kGCDWebServerHTTPStatusCode_NetworkAuthenticationRequired = 511
+};

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h
new file mode 100644
index 0000000..1ed54e8
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h
@@ -0,0 +1,228 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#import <os/object.h>
+#import <sys/socket.h>
+
+/**
+ *  All GCDWebServer headers.
+ */
+
+#import "GCDWebServerHTTPStatusCodes.h"
+#import "GCDWebServerFunctions.h"
+
+#import "GCDWebServer.h"
+#import "GCDWebServerConnection.h"
+
+#import "GCDWebServerDataRequest.h"
+#import "GCDWebServerFileRequest.h"
+#import "GCDWebServerMultiPartFormRequest.h"
+#import "GCDWebServerURLEncodedFormRequest.h"
+
+#import "GCDWebServerDataResponse.h"
+#import "GCDWebServerErrorResponse.h"
+#import "GCDWebServerFileResponse.h"
+#import "GCDWebServerStreamedResponse.h"
+
+/**
+ *  Automatically detect if XLFacility is available and if so use it as a
+ *  logging facility.
+ */
+
+#if defined(__has_include) && __has_include("XLFacilityMacros.h")
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
+
+#undef XLOG_TAG
+#define XLOG_TAG @"gcdwebserver.internal"
+
+#import "XLFacilityMacros.h"
+
+#define GWS_LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__)
+#define GWS_LOG_VERBOSE(...) XLOG_VERBOSE(__VA_ARGS__)
+#define GWS_LOG_INFO(...) XLOG_INFO(__VA_ARGS__)
+#define GWS_LOG_WARNING(...) XLOG_WARNING(__VA_ARGS__)
+#define GWS_LOG_ERROR(...) XLOG_ERROR(__VA_ARGS__)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) XLOG_EXCEPTION(__EXCEPTION__)
+
+#define GWS_DCHECK(__CONDITION__) XLOG_DEBUG_CHECK(__CONDITION__)
+#define GWS_DNOT_REACHED() XLOG_DEBUG_UNREACHABLE()
+
+/**
+ *  Automatically detect if CocoaLumberJack is available and if so use
+ *  it as a logging facility.
+ */
+
+#elif defined(__has_include) && __has_include("DDLogMacros.h")
+
+#import "DDLogMacros.h"
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_COCOALUMBERJACK__
+
+#undef LOG_LEVEL_DEF
+#define LOG_LEVEL_DEF GCDWebServerLogLevel
+extern int GCDWebServerLogLevel;
+
+#define GWS_LOG_DEBUG(...) DDLogDebug(__VA_ARGS__)
+#define GWS_LOG_VERBOSE(...) DDLogVerbose(__VA_ARGS__)
+#define GWS_LOG_INFO(...) DDLogInfo(__VA_ARGS__)
+#define GWS_LOG_WARNING(...) DDLogWarn(__VA_ARGS__)
+#define GWS_LOG_ERROR(...) DDLogError(__VA_ARGS__)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) DDLogError(@"%@", __EXCEPTION__)
+
+/**
+ *  Check if a custom logging facility should be used instead.
+ */
+
+#elif defined(__GCDWEBSERVER_LOGGING_HEADER__)
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
+
+#import __GCDWEBSERVER_LOGGING_HEADER__
+
+/**
+ *  If all of the above fail, then use GCDWebServer built-in
+ *  logging facility.
+ */
+
+#else
+
+#define __GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__
+
+typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
+  kGCDWebServerLoggingLevel_Debug = 0,
+  kGCDWebServerLoggingLevel_Verbose,
+  kGCDWebServerLoggingLevel_Info,
+  kGCDWebServerLoggingLevel_Warning,
+  kGCDWebServerLoggingLevel_Error,
+  kGCDWebServerLoggingLevel_Exception,
+};
+
+extern GCDWebServerLoggingLevel GCDWebServerLogLevel;
+extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* format, ...) NS_FORMAT_FUNCTION(2, 3);
+
+#if DEBUG
+#define GWS_LOG_DEBUG(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Debug) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Debug, __VA_ARGS__); } while (0)
+#else
+#define GWS_LOG_DEBUG(...)
+#endif
+#define GWS_LOG_VERBOSE(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Verbose) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Verbose, __VA_ARGS__); } while (0)
+#define GWS_LOG_INFO(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Info) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Info, __VA_ARGS__); } while (0)
+#define GWS_LOG_WARNING(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Warning) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Warning, __VA_ARGS__); } while (0)
+#define GWS_LOG_ERROR(...) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Error) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Error, __VA_ARGS__); } while (0)
+#define GWS_LOG_EXCEPTION(__EXCEPTION__) do { if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Exception) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Exception, @"%@", __EXCEPTION__); } while (0)
+
+#endif
+
+/**
+ *  Consistency check macros used when building Debug only.
+ */
+
+#if !defined(GWS_DCHECK) || !defined(GWS_DNOT_REACHED)
+
+#if DEBUG
+
+#define GWS_DCHECK(__CONDITION__) \
+  do { \
+    if (!(__CONDITION__)) { \
+      abort(); \
+    } \
+  } while (0)
+#define GWS_DNOT_REACHED() abort()
+
+#else
+
+#define GWS_DCHECK(__CONDITION__)
+#define GWS_DNOT_REACHED()
+
+#endif
+
+#endif
+
+/**
+ *  GCDWebServer internal constants and APIs.
+ */
+
+#define kGCDWebServerDefaultMimeType @"application/octet-stream"
+#define kGCDWebServerGCDQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
+#define kGCDWebServerErrorDomain @"GCDWebServerErrorDomain"
+
+static inline BOOL GCDWebServerIsValidByteRange(NSRange range) {
+  return ((range.location != NSUIntegerMax) || (range.length > 0));
+}
+
+static inline NSError* GCDWebServerMakePosixError(int code) {
+  return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithUTF8String:strerror(code)]}];
+}
+
+extern void GCDWebServerInitializeFunctions();
+extern NSString* GCDWebServerNormalizeHeaderValue(NSString* value);
+extern NSString* GCDWebServerTruncateHeaderValue(NSString* value);
+extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSString* attribute);
+extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
+extern BOOL GCDWebServerIsTextContentType(NSString* type);
+extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType);
+extern NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) NS_FORMAT_FUNCTION(1,2);
+extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL includeService);
+
+@interface GCDWebServerConnection ()
+- (id)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket;
+@end
+
+@interface GCDWebServer ()
+@property(nonatomic, readonly) NSArray* handlers;
+@property(nonatomic, readonly) NSString* serverName;
+@property(nonatomic, readonly) NSString* authenticationRealm;
+@property(nonatomic, readonly) NSDictionary* authenticationBasicAccounts;
+@property(nonatomic, readonly) NSDictionary* authenticationDigestAccounts;
+@property(nonatomic, readonly) BOOL shouldAutomaticallyMapHEADToGET;
+- (void)willStartConnection:(GCDWebServerConnection*)connection;
+- (void)didEndConnection:(GCDWebServerConnection*)connection;
+@end
+
+@interface GCDWebServerHandler : NSObject
+@property(nonatomic, readonly) GCDWebServerMatchBlock matchBlock;
+@property(nonatomic, readonly) GCDWebServerAsyncProcessBlock asyncProcessBlock;
+@end
+
+@interface GCDWebServerRequest ()
+@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
+- (void)prepareForWriting;
+- (BOOL)performOpen:(NSError**)error;
+- (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
+- (BOOL)performClose:(NSError**)error;
+- (void)setAttribute:(id)attribute forKey:(NSString*)key;
+@end
+
+@interface GCDWebServerResponse ()
+@property(nonatomic, readonly) NSDictionary* additionalHeaders;
+@property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
+- (void)prepareForReading;
+- (BOOL)performOpen:(NSError**)error;
+- (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
+- (void)performClose;
+@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h
new file mode 100644
index 0000000..3b517b6
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h
@@ -0,0 +1,182 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#import <Foundation/Foundation.h>
+
+/**
+ *  Attribute key to retrieve an NSArray containing NSStrings from a GCDWebServerRequest
+ *  with the contents of any regular expression captures done on the request path.
+ *
+ *  @warning This attribute will only be set on the request if adding a handler using 
+ *  -addHandlerForMethod:pathRegex:requestClass:processBlock:.
+ */
+extern NSString* const GCDWebServerRequestAttribute_RegexCaptures;
+
+/**
+ *  This protocol is used by the GCDWebServerConnection to communicate with
+ *  the GCDWebServerRequest and write the received HTTP body data.
+ *
+ *  Note that multiple GCDWebServerBodyWriter objects can be chained together
+ *  internally e.g. to automatically decode gzip encoded content before
+ *  passing it on to the GCDWebServerRequest.
+ *
+ *  @warning These methods can be called on any GCD thread.
+ */
+@protocol GCDWebServerBodyWriter <NSObject>
+
+/**
+ *  This method is called before any body data is received.
+ *
+ *  It should return YES on success or NO on failure and set the "error" argument
+ *  which is guaranteed to be non-NULL.
+ */
+- (BOOL)open:(NSError**)error;
+
+/**
+ *  This method is called whenever body data has been received.
+ *
+ *  It should return YES on success or NO on failure and set the "error" argument
+ *  which is guaranteed to be non-NULL.
+ */
+- (BOOL)writeData:(NSData*)data error:(NSError**)error;
+
+/**
+ *  This method is called after all body data has been received.
+ *
+ *  It should return YES on success or NO on failure and set the "error" argument
+ *  which is guaranteed to be non-NULL.
+ */
+- (BOOL)close:(NSError**)error;
+
+@end
+
+/**
+ *  The GCDWebServerRequest class is instantiated by the GCDWebServerConnection
+ *  after the HTTP headers have been received. Each instance wraps a single HTTP
+ *  request. If a body is present, the methods from the GCDWebServerBodyWriter
+ *  protocol will be called by the GCDWebServerConnection to receive it.
+ *
+ *  The default implementation of the GCDWebServerBodyWriter protocol on the class
+ *  simply ignores the body data.
+ *
+ *  @warning GCDWebServerRequest instances can be created and used on any GCD thread.
+ */
+@interface GCDWebServerRequest : NSObject <GCDWebServerBodyWriter>
+
+/**
+ *  Returns the HTTP method for the request.
+ */
+@property(nonatomic, readonly) NSString* method;
+
+/**
+ *  Returns the URL for the request.
+ */
+@property(nonatomic, readonly) NSURL* URL;
+
+/**
+ *  Returns the HTTP headers for the request.
+ */
+@property(nonatomic, readonly) NSDictionary* headers;
+
+/**
+ *  Returns the path component of the URL for the request.
+ */
+@property(nonatomic, readonly) NSString* path;
+
+/**
+ *  Returns the parsed and unescaped query component of the URL for the request.
+ *
+ *  @warning This property will be nil if there is no query in the URL.
+ */
+@property(nonatomic, readonly) NSDictionary* query;
+
+/**
+ *  Returns the content type for the body of the request parsed from the
+ *  "Content-Type" header.
+ *
+ *  This property will be nil if the request has no body or set to
+ *  "application/octet-stream" if a body is present but there was no
+ *  "Content-Type" header.
+ */
+@property(nonatomic, readonly) NSString* contentType;
+
+/**
+ *  Returns the content length for the body of the request parsed from the
+ *  "Content-Length" header.
+ *
+ *  This property will be set to "NSUIntegerMax" if the request has no body or
+ *  if there is a body but no "Content-Length" header, typically because
+ *  chunked transfer encoding is used.
+ */
+@property(nonatomic, readonly) NSUInteger contentLength;
+
+/**
+ *  Returns the parsed "If-Modified-Since" header or nil if absent or malformed.
+ */
+@property(nonatomic, readonly) NSDate* ifModifiedSince;
+
+/**
+ *  Returns the parsed "If-None-Match" header or nil if absent or malformed.
+ */
+@property(nonatomic, readonly) NSString* ifNoneMatch;
+
+/**
+ *  Returns the parsed "Range" header or (NSUIntegerMax, 0) if absent or malformed.
+ *  The range will be set to (offset, length) if expressed from the beginning
+ *  of the entity body, or (NSUIntegerMax, length) if expressed from its end.
+ */
+@property(nonatomic, readonly) NSRange byteRange;
+
+/**
+ *  Returns YES if the client supports gzip content encoding according to the
+ *  "Accept-Encoding" header.
+ */
+@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
+
+/**
+ *  This method is the designated initializer for the class.
+ */
+- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query;
+
+/**
+ *  Convenience method that checks if the contentType property is defined.
+ */
+- (BOOL)hasBody;
+
+/**
+ *  Convenience method that checks if the byteRange property is defined.
+ */
+- (BOOL)hasByteRange;
+
+/**
+ *  Retrieves an attribute associated with this request using the given key.
+ *
+ *  @return The attribute value for the key.
+ */
+- (id)attributeForKey:(NSString*)key;
+
+@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/2504faa4/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
----------------------------------------------------------------------
diff --git a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
new file mode 100644
index 0000000..cc14993
--- /dev/null
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
@@ -0,0 +1,319 @@
+/*
+ Copyright (c) 2012-2014, Pierre-Olivier Latour
+ All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * The name of Pierre-Olivier Latour may not be used to endorse
+ or promote products derived from this software without specific
+ prior written permission.
+ 
+ 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 PIERRE-OLIVIER LATOUR 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.
+ */
+
+#if !__has_feature(objc_arc)
+#error GCDWebServer requires ARC
+#endif
+
+#import <zlib.h>
+
+#import "GCDWebServerPrivate.h"
+
+NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerRequestAttribute_RegexCaptures";
+
+#define kZlibErrorDomain @"ZlibErrorDomain"
+#define kGZipInitialBufferSize (256 * 1024)
+
+@interface GCDWebServerBodyDecoder : NSObject <GCDWebServerBodyWriter>
+- (id)initWithRequest:(GCDWebServerRequest*)request writer:(id<GCDWebServerBodyWriter>)writer;
+@end
+
+@interface GCDWebServerGZipDecoder : GCDWebServerBodyDecoder
+@end
+
+@interface GCDWebServerBodyDecoder () {
+@private
+  GCDWebServerRequest* __unsafe_unretained _request;
+  id<GCDWebServerBodyWriter> __unsafe_unretained _writer;
+}
+@end
+
+@implementation GCDWebServerBodyDecoder
+
+- (id)initWithRequest:(GCDWebServerRequest*)request writer:(id<GCDWebServerBodyWriter>)writer {
+  if ((self = [super init])) {
+    _request = request;
+    _writer = writer;
+  }
+  return self;
+}
+
+- (BOOL)open:(NSError**)error {
+  return [_writer open:error];
+}
+
+- (BOOL)writeData:(NSData*)data error:(NSError**)error {
+  return [_writer writeData:data error:error];
+}
+
+- (BOOL)close:(NSError**)error {
+  return [_writer close:error];
+}
+
+@end
+
+@interface GCDWebServerGZipDecoder () {
+@private
+  z_stream _stream;
+  BOOL _finished;
+}
+@end
+
+@implementation GCDWebServerGZipDecoder
+
+- (BOOL)open:(NSError**)error {
+  int result = inflateInit2(&_stream, 15 + 16);
+  if (result != Z_OK) {
+    *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+    return NO;
+  }
+  if (![super open:error]) {
+    deflateEnd(&_stream);
+    return NO;
+  }
+  return YES;
+}
+
+- (BOOL)writeData:(NSData*)data error:(NSError**)error {
+  GWS_DCHECK(!_finished);
+  _stream.next_in = (Bytef*)data.bytes;
+  _stream.avail_in = (uInt)data.length;
+  NSMutableData* decodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
+  if (decodedData == nil) {
+    GWS_DNOT_REACHED();
+    return NO;
+  }
+  NSUInteger length = 0;
+  while (1) {
+    NSUInteger maxLength = decodedData.length - length;
+    _stream.next_out = (Bytef*)((char*)decodedData.mutableBytes + length);
+    _stream.avail_out = (uInt)maxLength;
+    int result = inflate(&_stream, Z_NO_FLUSH);
+    if ((result != Z_OK) && (result != Z_STREAM_END)) {
+      *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
+      return NO;
+    }
+    length += maxLength - _stream.avail_out;
+    if (_stream.avail_out > 0) {
+      if (result == Z_STREAM_END) {
+        _finished = YES;
+      }
+      break;
+    }
+    decodedData.length = 2 * decodedData.length;  // zlib has used all the output buffer so resize it and try again in case more data is available
+  }
+  decodedData.length = length;
+  BOOL success = length ? [super writeData:decodedData error:error] : YES;  // No need to call writer if we have no data yet
+  return success;
+}
+
+- (BOOL)close:(NSError**)error {
+  GWS_DCHECK(_finished);
+  inflateEnd(&_stream);
+  return [super close:error];
+}
+
+@end
+
+@interface GCDWebServerRequest () {
+@private
+  NSString* _method;
+  NSURL* _url;
+  NSDictionary* _headers;
+  NSString* _path;
+  NSDictionary* _query;
+  NSString* _type;
+  BOOL _chunked;
+  NSUInteger _length;
+  NSDate* _modifiedSince;
+  NSString* _noneMatch;
+  NSRange _range;
+  BOOL _gzipAccepted;
+  
+  BOOL _opened;
+  NSMutableArray* _decoders;
+  NSMutableDictionary* _attributes;
+  id<GCDWebServerBodyWriter> __unsafe_unretained _writer;
+}
+@end
+
+@implementation GCDWebServerRequest : NSObject
+
+@synthesize method=_method, URL=_url, headers=_headers, path=_path, query=_query, contentType=_type, contentLength=_length, ifModifiedSince=_modifiedSince, ifNoneMatch=_noneMatch,
+            byteRange=_range, acceptsGzipContentEncoding=_gzipAccepted, usesChunkedTransferEncoding=_chunked;
+
+- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
+  if ((self = [super init])) {
+    _method = [method copy];
+    _url = url;
+    _headers = headers;
+    _path = [path copy];
+    _query = query;
+    
+    _type = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Content-Type"]);
+    _chunked = [GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Transfer-Encoding"]) isEqualToString:@"chunked"];
+    NSString* lengthHeader = [_headers objectForKey:@"Content-Length"];
+    if (lengthHeader) {
+      NSInteger length = [lengthHeader integerValue];
+      if (_chunked || (length < 0)) {
+        GWS_DNOT_REACHED();
+        return nil;
+      }
+      _length = length;
+      if (_type == nil) {
+        _type = kGCDWebServerDefaultMimeType;
+      }
+    } else if (_chunked) {
+      if (_type == nil) {
+        _type = kGCDWebServerDefaultMimeType;
+      }
+      _length = NSUIntegerMax;
+    } else {
+      if (_type) {
+        GWS_DNOT_REACHED();
+        return nil;
+      }
+      _length = NSUIntegerMax;
+    }
+    
+    NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"];
+    if (modifiedHeader) {
+      _modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy];
+    }
+    _noneMatch = [_headers objectForKey:@"If-None-Match"];
+    
+    _range = NSMakeRange(NSUIntegerMax, 0);
+    NSString* rangeHeader = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Range"]);
+    if (rangeHeader) {
+      if ([rangeHeader hasPrefix:@"bytes="]) {
+        NSArray* components = [[rangeHeader substringFromIndex:6] componentsSeparatedByString:@","];
+        if (components.count == 1) {
+          components = [[components firstObject] componentsSeparatedByString:@"-"];
+          if (components.count == 2) {
+            NSString* startString = [components objectAtIndex:0];
+            NSInteger startValue = [startString integerValue];
+            NSString* endString = [components objectAtIndex:1];
+            NSInteger endValue = [endString integerValue];
+            if (startString.length && (startValue >= 0) && endString.length && (endValue >= startValue)) {  // The second 500 bytes: "500-999"
+              _range.location = startValue;
+              _range.length = endValue - startValue + 1;
+            } else if (startString.length && (startValue >= 0)) {  // The bytes after 9500 bytes: "9500-"
+              _range.location = startValue;
+              _range.length = NSUIntegerMax;
+            } else if (endString.length && (endValue > 0)) {  // The final 500 bytes: "-500"
+              _range.location = NSUIntegerMax;
+              _range.length = endValue;
+            }
+          }
+        }
+      }
+      if ((_range.location == NSUIntegerMax) && (_range.length == 0)) {  // Ignore "Range" header if syntactically invalid
+        GWS_LOG_WARNING(@"Failed to parse 'Range' header \"%@\" for url: %@", rangeHeader, url);
+      }
+    }
+    
+    if ([[_headers objectForKey:@"Accept-Encoding"] rangeOfString:@"gzip"].location != NSNotFound) {
+      _gzipAccepted = YES;
+    }
+    
+    _decoders = [[NSMutableArray alloc] init];
+    _attributes = [[NSMutableDictionary alloc] init];
+  }
+  return self;
+}
+
+- (BOOL)hasBody {
+  return _type ? YES : NO;
+}
+
+- (BOOL)hasByteRange {
+  return GCDWebServerIsValidByteRange(_range);
+}
+
+- (id)attributeForKey:(NSString*)key {
+  return [_attributes objectForKey:key];
+}
+
+- (BOOL)open:(NSError**)error {
+  return YES;
+}
+
+- (BOOL)writeData:(NSData*)data error:(NSError**)error {
+  return YES;
+}
+
+- (BOOL)close:(NSError**)error {
+  return YES;
+}
+
+- (void)prepareForWriting {
+  _writer = self;
+  if ([GCDWebServerNormalizeHeaderValue([self.headers objectForKey:@"Content-Encoding"]) isEqualToString:@"gzip"]) {
+    GCDWebServerGZipDecoder* decoder = [[GCDWebServerGZipDecoder alloc] initWithRequest:self writer:_writer];
+    [_decoders addObject:decoder];
+    _writer = decoder;
+  }
+}
+
+- (BOOL)performOpen:(NSError**)error {
+  GWS_DCHECK(_type);
+  GWS_DCHECK(_writer);
+  if (_opened) {
+    GWS_DNOT_REACHED();
+    return NO;
+  }
+  _opened = YES;
+  return [_writer open:error];
+}
+
+- (BOOL)performWriteData:(NSData*)data error:(NSError**)error {
+  GWS_DCHECK(_opened);
+  return [_writer writeData:data error:error];
+}
+
+- (BOOL)performClose:(NSError**)error {
+  GWS_DCHECK(_opened);
+  return [_writer close:error];
+}
+
+- (void)setAttribute:(id)attribute forKey:(NSString*)key {
+  [_attributes setValue:attribute forKey:key];
+}
+
+- (NSString*)description {
+  NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
+  for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
+    [description appendFormat:@"\n  %@ = %@", argument, [_query objectForKey:argument]];
+  }
+  [description appendString:@"\n"];
+  for (NSString* header in [[_headers allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
+    [description appendFormat:@"\n%@: %@", header, [_headers objectForKey:header]];
+  }
+  return description;
+}
+
+@end


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org