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 2016/07/25 07:57:37 UTC

[51/57] [abbrv] cordova-plugins git commit: Merge commit '394cfb12f80de35255a506c0dcbf4a21910e849a'

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
index cc14993,0000000..dc929a7
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m
@@@ -1,319 -1,0 +1,334 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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];
++    if (error) {
++      *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];
++      if (error) {
++        *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;
++  NSData* _localAddress;
++  NSData* _remoteAddress;
 +  
 +  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;
++            byteRange=_range, acceptsGzipContentEncoding=_gzipAccepted, usesChunkedTransferEncoding=_chunked, localAddressData=_localAddress, remoteAddressData=_remoteAddress;
 +
 +- (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_LOG_WARNING(@"Invalid 'Content-Length' header '%@' for '%@' request on \"%@\"", lengthHeader, _method, _url);
 +        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;
++        GWS_LOG_WARNING(@"Ignoring 'Content-Type' header for '%@' request on \"%@\"", _method, _url);
++        _type = nil;  // Content-Type without Content-Length or chunked-encoding doesn't make sense
 +      }
 +      _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*)localAddressString {
++  return GCDWebServerStringFromSockAddr(_localAddress.bytes, YES);
++}
++
++- (NSString*)remoteAddressString {
++  return GCDWebServerStringFromSockAddr(_remoteAddress.bytes, YES);
++}
++
 +- (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

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
index 01ef2ab,0000000..2ec2dee
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
@@@ -1,208 -1,0 +1,208 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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>
 +
 +/**
 + *  The GCDWebServerBodyReaderCompletionBlock is passed by GCDWebServer to the
 + *  GCDWebServerBodyReader object when reading data from it asynchronously.
 + */
 +typedef void (^GCDWebServerBodyReaderCompletionBlock)(NSData* data, NSError* error);
 +
 +/**
 + *  This protocol is used by the GCDWebServerConnection to communicate with
 + *  the GCDWebServerResponse and read the HTTP body data to send.
 + *
 + *  Note that multiple GCDWebServerBodyReader objects can be chained together
 + *  internally e.g. to automatically apply gzip encoding to the content before
 + *  passing it on to the GCDWebServerResponse.
 + *
 + *  @warning These methods can be called on any GCD thread.
 + */
 +@protocol GCDWebServerBodyReader <NSObject>
 +
 +@required
 +
 +/**
 + *  This method is called before any body data is sent.
 + *
 + *  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 is sent.
 + *
 + *  It should return a non-empty NSData if there is body data available,
 + *  or an empty NSData there is no more body data, or nil on error and set
 + *  the "error" argument which is guaranteed to be non-NULL.
 + */
 +- (NSData*)readData:(NSError**)error;
 +
 +/**
 + *  This method is called after all body data has been sent.
 + */
 +- (void)close;
 +
 +@optional
 +
 +/**
 + *  If this method is implemented, it will be preferred over -readData:.
 + *
 + *  It must call the passed block when data is available, passing a non-empty
 + *  NSData if there is body data available, or an empty NSData there is no more
 + *  body data, or nil on error and pass an NSError along.
 + */
 +- (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
 +
 +@end
 +
 +/**
 + *  The GCDWebServerResponse class is used to wrap a single HTTP response.
 + *  It is instantiated by the handler of the GCDWebServer that handled the request.
 + *  If a body is present, the methods from the GCDWebServerBodyReader protocol
 + *  will be called by the GCDWebServerConnection to send it.
 + *
 + *  The default implementation of the GCDWebServerBodyReader protocol
 + *  on the class simply returns an empty body.
 + *
 + *  @warning GCDWebServerResponse instances can be created and used on any GCD thread.
 + */
 +@interface GCDWebServerResponse : NSObject <GCDWebServerBodyReader>
 +
 +/**
 + *  Sets the content type for the body of the response.
 + *
 + *  The default value is nil i.e. the response has no body.
 + *
 + *  @warning This property must be set if a body is present.
 + */
 +@property(nonatomic, copy) NSString* contentType;
 +
 +/**
 + *  Sets the content length for the body of the response. If a body is present
 + *  but this property is set to "NSUIntegerMax", this means the length of the body
 + *  cannot be known ahead of time. Chunked transfer encoding will be
 + *  automatically enabled by the GCDWebServerConnection to comply with HTTP/1.1
 + *  specifications.
 + *
 + *  The default value is "NSUIntegerMax" i.e. the response has no body or its length
 + *  is undefined.
 + */
 +@property(nonatomic) NSUInteger contentLength;
 +
 +/**
 + *  Sets the HTTP status code for the response.
 + *
 + *  The default value is 200 i.e. "OK".
 + */
 +@property(nonatomic) NSInteger statusCode;
 +
 +/**
 + *  Sets the caching hint for the response using the "Cache-Control" header.
 + *  This value is expressed in seconds.
 + *
 + *  The default value is 0 i.e. "no-cache".
 + */
 +@property(nonatomic) NSUInteger cacheControlMaxAge;
 +
 +/**
 + *  Sets the last modified date for the response using the "Last-Modified" header.
 + *
 + *  The default value is nil.
 + */
 +@property(nonatomic, retain) NSDate* lastModifiedDate;
 +
 +/**
 + *  Sets the ETag for the response using the "ETag" header.
 + *
 + *  The default value is nil.
 + */
 +@property(nonatomic, copy) NSString* eTag;
 +
 +/**
 + *  Enables gzip encoding for the response body.
 + *
 + *  The default value is NO.
 + *
 + *  @warning Enabling gzip encoding will remove any "Content-Length" header
 + *  since the length of the body is not known anymore. The client will still
 + *  be able to determine the body length when connection is closed per
 + *  HTTP/1.1 specifications.
 + */
 +@property(nonatomic, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled;
 +
 +/**
 + *  Creates an empty response.
 + */
 ++ (instancetype)response;
 +
 +/**
 + *  This method is the designated initializer for the class.
 + */
 +- (instancetype)init;
 +
 +/**
 + *  Sets an additional HTTP header on the response.
 + *  Pass a nil value to remove an additional header.
 + *
 + *  @warning Do not attempt to override the primary headers used
 + *  by GCDWebServerResponse like "Content-Type", "ETag", etc...
 + */
 +- (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header;
 +
 +/**
 + *  Convenience method that checks if the contentType property is defined.
 + */
 +- (BOOL)hasBody;
 +
 +@end
 +
 +@interface GCDWebServerResponse (Extensions)
 +
 +/**
 + *  Creates a empty response with a specific HTTP status code.
 + */
 ++ (instancetype)responseWithStatusCode:(NSInteger)statusCode;
 +
 +/**
 + *  Creates an HTTP redirect response to a new URL.
 + */
 ++ (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
 +
 +/**
 + *  Initializes an empty response with a specific HTTP status code.
 + */
 +- (instancetype)initWithStatusCode:(NSInteger)statusCode;
 +
 +/**
 + *  Initializes an HTTP redirect response to a new URL.
 + */
 +- (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m
index b0a220b,0000000..8357ab7
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m
@@@ -1,305 -1,0 +1,309 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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"
 +
 +#define kZlibErrorDomain @"ZlibErrorDomain"
 +#define kGZipInitialBufferSize (256 * 1024)
 +
 +@interface GCDWebServerBodyEncoder : NSObject <GCDWebServerBodyReader>
 +- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader;
 +@end
 +
 +@interface GCDWebServerGZipEncoder : GCDWebServerBodyEncoder
 +@end
 +
 +@interface GCDWebServerBodyEncoder () {
 +@private
 +  GCDWebServerResponse* __unsafe_unretained _response;
 +  id<GCDWebServerBodyReader> __unsafe_unretained _reader;
 +}
 +@end
 +
 +@implementation GCDWebServerBodyEncoder
 +
 +- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader {
 +  if ((self = [super init])) {
 +    _response = response;
 +    _reader = reader;
 +  }
 +  return self;
 +}
 +
 +- (BOOL)open:(NSError**)error {
 +  return [_reader open:error];
 +}
 +
 +- (NSData*)readData:(NSError**)error {
 +  return [_reader readData:error];
 +}
 +
 +- (void)close {
 +  [_reader close];
 +}
 +
 +@end
 +
 +@interface GCDWebServerGZipEncoder () {
 +@private
 +  z_stream _stream;
 +  BOOL _finished;
 +}
 +@end
 +
 +@implementation GCDWebServerGZipEncoder
 +
 +- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader {
 +  if ((self = [super initWithResponse:response reader:reader])) {
 +    response.contentLength = NSUIntegerMax;  // Make sure "Content-Length" header is not set since we don't know it
 +    [response setValue:@"gzip" forAdditionalHeader:@"Content-Encoding"];
 +  }
 +  return self;
 +}
 +
 +- (BOOL)open:(NSError**)error {
 +  int result = deflateInit2(&_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
 +  if (result != Z_OK) {
-     *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
++    if (error) {
++      *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
++    }
 +    return NO;
 +  }
 +  if (![super open:error]) {
 +    deflateEnd(&_stream);
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (NSData*)readData:(NSError**)error {
 +  NSMutableData* encodedData;
 +  if (_finished) {
 +    encodedData = [[NSMutableData alloc] init];
 +  } else {
 +    encodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
 +    if (encodedData == nil) {
 +      GWS_DNOT_REACHED();
 +      return nil;
 +    }
 +    NSUInteger length = 0;
 +    do {
 +      NSData* data = [super readData:error];
 +      if (data == nil) {
 +        return nil;
 +      }
 +      _stream.next_in = (Bytef*)data.bytes;
 +      _stream.avail_in = (uInt)data.length;
 +      while (1) {
 +        NSUInteger maxLength = encodedData.length - length;
 +        _stream.next_out = (Bytef*)((char*)encodedData.mutableBytes + length);
 +        _stream.avail_out = (uInt)maxLength;
 +        int result = deflate(&_stream, data.length ? Z_NO_FLUSH : Z_FINISH);
 +        if (result == Z_STREAM_END) {
 +          _finished = YES;
 +        } else if (result != Z_OK) {
-           *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
++          if (error) {
++            *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
++          }
 +          return nil;
 +        }
 +        length += maxLength - _stream.avail_out;
 +        if (_stream.avail_out > 0) {
 +          break;
 +        }
 +        encodedData.length = 2 * encodedData.length;  // zlib has used all the output buffer so resize it and try again in case more data is available
 +      }
 +      GWS_DCHECK(_stream.avail_in == 0);
 +    } while (length == 0);  // Make sure we don't return an empty NSData if not in finished state
 +    encodedData.length = length;
 +  }
 +  return encodedData;
 +}
 +
 +- (void)close {
 +  deflateEnd(&_stream);
 +  [super close];
 +}
 +
 +@end
 +
 +@interface GCDWebServerResponse () {
 +@private
 +  NSString* _type;
 +  NSUInteger _length;
 +  NSInteger _status;
 +  NSUInteger _maxAge;
 +  NSDate* _lastModified;
 +  NSString* _eTag;
 +  NSMutableDictionary* _headers;
 +  BOOL _chunked;
 +  BOOL _gzipped;
 +  
 +  BOOL _opened;
 +  NSMutableArray* _encoders;
 +  id<GCDWebServerBodyReader> __unsafe_unretained _reader;
 +}
 +@end
 +
 +@implementation GCDWebServerResponse
 +
 +@synthesize contentType=_type, contentLength=_length, statusCode=_status, cacheControlMaxAge=_maxAge, lastModifiedDate=_lastModified, eTag=_eTag,
 +            gzipContentEncodingEnabled=_gzipped, additionalHeaders=_headers;
 +
 ++ (instancetype)response {
 +  return [[[self class] alloc] init];
 +}
 +
 +- (instancetype)init {
 +  if ((self = [super init])) {
 +    _type = nil;
 +    _length = NSUIntegerMax;
 +    _status = kGCDWebServerHTTPStatusCode_OK;
 +    _maxAge = 0;
 +    _headers = [[NSMutableDictionary alloc] init];
 +    _encoders = [[NSMutableArray alloc] init];
 +  }
 +  return self;
 +}
 +
 +- (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header {
 +  [_headers setValue:value forKey:header];
 +}
 +
 +- (BOOL)hasBody {
 +  return _type ? YES : NO;
 +}
 +
 +- (BOOL)usesChunkedTransferEncoding {
 +  return (_type != nil) && (_length == NSUIntegerMax);
 +}
 +
 +- (BOOL)open:(NSError**)error {
 +  return YES;
 +}
 +
 +- (NSData*)readData:(NSError**)error {
 +  return [NSData data];
 +}
 +
 +- (void)close {
 +  ;
 +}
 +
 +- (void)prepareForReading {
 +  _reader = self;
 +  if (_gzipped) {
 +    GCDWebServerGZipEncoder* encoder = [[GCDWebServerGZipEncoder alloc] initWithResponse:self reader:_reader];
 +    [_encoders addObject:encoder];
 +    _reader = encoder;
 +  }
 +}
 +
 +- (BOOL)performOpen:(NSError**)error {
 +  GWS_DCHECK(_type);
 +  GWS_DCHECK(_reader);
 +  if (_opened) {
 +    GWS_DNOT_REACHED();
 +    return NO;
 +  }
 +  _opened = YES;
 +  return [_reader open:error];
 +}
 +
 +- (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
 +  if ([_reader respondsToSelector:@selector(asyncReadDataWithCompletion:)]) {
-     [_reader asyncReadDataWithCompletion:block];
++    [_reader asyncReadDataWithCompletion:[block copy]];
 +  } else {
 +    NSError* error = nil;
 +    NSData* data = [_reader readData:&error];
 +    block(data, error);
 +  }
 +}
 +
 +- (void)performClose {
 +  GWS_DCHECK(_opened);
 +  [_reader close];
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithFormat:@"Status Code = %i", (int)_status];
 +  if (_type) {
 +    [description appendFormat:@"\nContent Type = %@", _type];
 +  }
 +  if (_length != NSUIntegerMax) {
 +    [description appendFormat:@"\nContent Length = %lu", (unsigned long)_length];
 +  }
 +  [description appendFormat:@"\nCache Control Max Age = %lu", (unsigned long)_maxAge];
 +  if (_lastModified) {
 +    [description appendFormat:@"\nLast Modified Date = %@", _lastModified];
 +  }
 +  if (_eTag) {
 +    [description appendFormat:@"\nETag = %@", _eTag];
 +  }
 +  if (_headers.count) {
 +    [description appendString:@"\n"];
 +    for (NSString* header in [[_headers allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
 +      [description appendFormat:@"\n%@: %@", header, [_headers objectForKey:header]];
 +    }
 +  }
 +  return description;
 +}
 +
 +@end
 +
 +@implementation GCDWebServerResponse (Extensions)
 +
 ++ (instancetype)responseWithStatusCode:(NSInteger)statusCode {
 +  return [[self alloc] initWithStatusCode:statusCode];
 +}
 +
 ++ (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent {
 +  return [[self alloc] initWithRedirect:location permanent:permanent];
 +}
 +
 +- (instancetype)initWithStatusCode:(NSInteger)statusCode {
 +  if ((self = [self init])) {
 +    self.statusCode = statusCode;
 +  }
 +  return self;
 +}
 +
 +- (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent {
 +  if ((self = [self init])) {
 +    self.statusCode = permanent ? kGCDWebServerHTTPStatusCode_MovedPermanently : kGCDWebServerHTTPStatusCode_TemporaryRedirect;
 +    [self setValue:[location absoluteString] forAdditionalHeader:@"Location"];
 +  }
 +  return self;
 +}
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
index ef94b97,0000000..5048d08
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
@@@ -1,60 -1,0 +1,60 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerRequest.h"
 +
 +/**
 + *  The GCDWebServerDataRequest subclass of GCDWebServerRequest stores the body
 + *  of the HTTP request in memory.
 + */
 +@interface GCDWebServerDataRequest : GCDWebServerRequest
 +
 +/**
 + *  Returns the data for the request body.
 + */
 +@property(nonatomic, readonly) NSData* data;
 +
 +@end
 +
 +@interface GCDWebServerDataRequest (Extensions)
 +
 +/**
 + *  Returns the data for the request body interpreted as text. If the content
 + *  type of the body is not a text one, or if an error occurs, nil is returned.
 + *
 + *  The text encoding used to interpret the data is extracted from the
 + *  "Content-Type" header or defaults to UTF-8.
 + */
 +@property(nonatomic, readonly) NSString* text;
 +
 +/**
 + *  Returns the data for the request body interpreted as a JSON object. If the
 + *  content type of the body is not JSON, or if an error occurs, nil is returned.
 + */
 +@property(nonatomic, readonly) id jsonObject;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m
index 4f0ed75,0000000..840e985
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m
@@@ -1,106 -1,0 +1,108 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerPrivate.h"
 +
 +@interface GCDWebServerDataRequest () {
 +@private
 +  NSMutableData* _data;
 +  
 +  NSString* _text;
 +  id _jsonObject;
 +}
 +@end
 +
 +@implementation GCDWebServerDataRequest
 +
 +@synthesize data=_data;
 +
 +- (BOOL)open:(NSError**)error {
 +  if (self.contentLength != NSUIntegerMax) {
 +    _data = [[NSMutableData alloc] initWithCapacity:self.contentLength];
 +  } else {
 +    _data = [[NSMutableData alloc] init];
 +  }
 +  if (_data == nil) {
-     *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
++    if (error) {
++      *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed allocating memory"}];
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (BOOL)writeData:(NSData*)data error:(NSError**)error {
 +  [_data appendData:data];
 +  return YES;
 +}
 +
 +- (BOOL)close:(NSError**)error {
 +  return YES;
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithString:[super description]];
 +  if (_data) {
 +    [description appendString:@"\n\n"];
 +    [description appendString:GCDWebServerDescribeData(_data, self.contentType)];
 +  }
 +  return description;
 +}
 +
 +@end
 +
 +@implementation GCDWebServerDataRequest (Extensions)
 +
 +- (NSString*)text {
 +  if (_text == nil) {
 +    if ([self.contentType hasPrefix:@"text/"]) {
 +      NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
 +      _text = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
 +    } else {
 +      GWS_DNOT_REACHED();
 +    }
 +  }
 +  return _text;
 +}
 +
 +- (id)jsonObject {
 +  if (_jsonObject == nil) {
 +    NSString* mimeType = GCDWebServerTruncateHeaderValue(self.contentType);
 +    if ([mimeType isEqualToString:@"application/json"] || [mimeType isEqualToString:@"text/json"] || [mimeType isEqualToString:@"text/javascript"]) {
 +      _jsonObject = [NSJSONSerialization JSONObjectWithData:_data options:0 error:NULL];
 +    } else {
 +      GWS_DNOT_REACHED();
 +    }
 +  }
 +  return _jsonObject;
 +}
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
index 427a800,0000000..ad29eab
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
@@@ -1,45 -1,0 +1,45 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerRequest.h"
 +
 +/**
 + *  The GCDWebServerFileRequest subclass of GCDWebServerRequest stores the body
 + *  of the HTTP request to a file on disk.
 + */
 +@interface GCDWebServerFileRequest : GCDWebServerRequest
 +
 +/**
 + *  Returns the path to the temporary file containing the request body.
 + *
 + *  @warning This temporary file will be automatically deleted when the
 + *  GCDWebServerFileRequest is deallocated. If you want to preserve this file,
 + *  you must move it to a different location beforehand.
 + */
 +@property(nonatomic, readonly) NSString* temporaryPath;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m
index d0c2118,0000000..adf67a5
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m
@@@ -1,103 -1,0 +1,109 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerPrivate.h"
 +
 +@interface GCDWebServerFileRequest () {
 +@private
 +  NSString* _temporaryPath;
 +  int _file;
 +}
 +@end
 +
 +@implementation GCDWebServerFileRequest
 +
 +@synthesize temporaryPath=_temporaryPath;
 +
 +- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
 +  if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
 +    _temporaryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
 +  }
 +  return self;
 +}
 +
 +- (void)dealloc {
 +  unlink([_temporaryPath fileSystemRepresentation]);
 +}
 +
 +- (BOOL)open:(NSError**)error {
 +  _file = open([_temporaryPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 +  if (_file <= 0) {
-     *error = GCDWebServerMakePosixError(errno);
++    if (error) {
++      *error = GCDWebServerMakePosixError(errno);
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (BOOL)writeData:(NSData*)data error:(NSError**)error {
 +  if (write(_file, data.bytes, data.length) != (ssize_t)data.length) {
-     *error = GCDWebServerMakePosixError(errno);
++    if (error) {
++      *error = GCDWebServerMakePosixError(errno);
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (BOOL)close:(NSError**)error {
 +  if (close(_file) < 0) {
-     *error = GCDWebServerMakePosixError(errno);
++    if (error) {
++      *error = GCDWebServerMakePosixError(errno);
++    }
 +    return NO;
 +  }
 +#ifdef __GCDWEBSERVER_ENABLE_TESTING__
 +  NSString* creationDateHeader = [self.headers objectForKey:@"X-GCDWebServer-CreationDate"];
 +  if (creationDateHeader) {
 +    NSDate* date = GCDWebServerParseISO8601(creationDateHeader);
 +    if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate: date} ofItemAtPath:_temporaryPath error:error]) {
 +      return NO;
 +    }
 +  }
 +  NSString* modifiedDateHeader = [self.headers objectForKey:@"X-GCDWebServer-ModifiedDate"];
 +  if (modifiedDateHeader) {
 +    NSDate* date = GCDWebServerParseRFC822(modifiedDateHeader);
 +    if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: date} ofItemAtPath:_temporaryPath error:error]) {
 +      return NO;
 +    }
 +  }
 +#endif
 +  return YES;
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithString:[super description]];
 +  [description appendFormat:@"\n\n{%@}", _temporaryPath];
 +  return description;
 +}
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
index 2463ca2,0000000..832c2e7
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
@@@ -1,132 -1,0 +1,132 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerRequest.h"
 +
 +/**
 + *  The GCDWebServerMultiPart class is an abstract class that wraps the content
 + *  of a part.
 + */
 +@interface GCDWebServerMultiPart : NSObject
 +
 +/**
 + *  Returns the control name retrieved from the part headers.
 + */
 +@property(nonatomic, readonly) NSString* controlName;
 +
 +/**
 + *  Returns the content type retrieved from the part headers or "text/plain"
 + *  if not available (per HTTP specifications).
 + */
 +@property(nonatomic, readonly) NSString* contentType;
 +
 +/**
 + *  Returns the MIME type component of the content type for the part.
 + */
 +@property(nonatomic, readonly) NSString* mimeType;
 +
 +@end
 +
 +/**
 + *  The GCDWebServerMultiPartArgument subclass of GCDWebServerMultiPart wraps
 + *  the content of a part as data in memory.
 + */
 +@interface GCDWebServerMultiPartArgument : GCDWebServerMultiPart
 +
 +/**
 + *  Returns the data for the part.
 + */
 +@property(nonatomic, readonly) NSData* data;
 +
 +/**
 + *  Returns the data for the part interpreted as text. If the content
 + *  type of the part is not a text one, or if an error occurs, nil is returned.
 + *
 + *  The text encoding used to interpret the data is extracted from the
 + *  "Content-Type" header or defaults to UTF-8.
 + */
 +@property(nonatomic, readonly) NSString* string;
 +
 +@end
 +
 +/**
 + *  The GCDWebServerMultiPartFile subclass of GCDWebServerMultiPart wraps
 + *  the content of a part as a file on disk.
 + */
 +@interface GCDWebServerMultiPartFile : GCDWebServerMultiPart
 +
 +/**
 + *  Returns the file name retrieved from the part headers.
 + */
 +@property(nonatomic, readonly) NSString* fileName;
 +
 +/**
 + *  Returns the path to the temporary file containing the part data.
 + *
 + *  @warning This temporary file will be automatically deleted when the
 + *  GCDWebServerMultiPartFile is deallocated. If you want to preserve this file,
 + *  you must move it to a different location beforehand.
 + */
 +@property(nonatomic, readonly) NSString* temporaryPath;
 +
 +@end
 +
 +/**
 + *  The GCDWebServerMultiPartFormRequest subclass of GCDWebServerRequest
 + *  parses the body of the HTTP request as a multipart encoded form.
 + */
 +@interface GCDWebServerMultiPartFormRequest : GCDWebServerRequest
 +
 +/**
 + *  Returns the argument parts from the multipart encoded form as
 + *  name / GCDWebServerMultiPartArgument pairs.
 + */
 +@property(nonatomic, readonly) NSArray* arguments;
 +
 +/**
 + *  Returns the files parts from the multipart encoded form as
 + *  name / GCDWebServerMultiPartFile pairs.
 + */
 +@property(nonatomic, readonly) NSArray* files;
 +
 +/**
 + *  Returns the MIME type for multipart encoded forms
 + *  i.e. "multipart/form-data".
 + */
 ++ (NSString*)mimeType;
 +
 +/**
 + *  Returns the first argument for a given control name or nil if not found.
 + */
 +- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name;
 +
 +/**
 + *  Returns the first file for a given control name or nil if not found.
 + */
 +- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
index e1c0015,0000000..c2fc9bf
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m
@@@ -1,439 -1,0 +1,445 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerPrivate.h"
 +
 +#define kMultiPartBufferSize (256 * 1024)
 +
 +typedef enum {
 +  kParserState_Undefined = 0,
 +  kParserState_Start,
 +  kParserState_Headers,
 +  kParserState_Content,
 +  kParserState_End
 +} ParserState;
 +
 +@interface GCDWebServerMIMEStreamParser : NSObject
 +- (id)initWithBoundary:(NSString*)boundary defaultControlName:(NSString*)name arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files;
 +- (BOOL)appendBytes:(const void*)bytes length:(NSUInteger)length;
 +- (BOOL)isAtEnd;
 +@end
 +
 +static NSData* _newlineData = nil;
 +static NSData* _newlinesData = nil;
 +static NSData* _dashNewlineData = nil;
 +
 +@interface GCDWebServerMultiPart () {
 +@private
 +  NSString* _controlName;
 +  NSString* _contentType;
 +  NSString* _mimeType;
 +}
 +@end
 +
 +@implementation GCDWebServerMultiPart
 +
 +@synthesize controlName=_controlName, contentType=_contentType, mimeType=_mimeType;
 +
 +- (id)initWithControlName:(NSString*)name contentType:(NSString*)type {
 +  if ((self = [super init])) {
 +    _controlName = [name copy];
 +    _contentType = [type copy];
 +    _mimeType = GCDWebServerTruncateHeaderValue(_contentType);
 +  }
 +  return self;
 +}
 +
 +@end
 +
 +@interface GCDWebServerMultiPartArgument () {
 +@private
 +  NSData* _data;
 +  NSString* _string;
 +}
 +@end
 +
 +@implementation GCDWebServerMultiPartArgument
 +
 +@synthesize data=_data, string=_string;
 +
 +- (id)initWithControlName:(NSString*)name contentType:(NSString*)type data:(NSData*)data {
 +  if ((self = [super initWithControlName:name contentType:type])) {
 +    _data = data;
 +    
 +    if ([self.contentType hasPrefix:@"text/"]) {
 +      NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
 +      _string = [[NSString alloc] initWithData:_data encoding:GCDWebServerStringEncodingFromCharset(charset)];
 +    }
 +  }
 +  return self;
 +}
 +
 +- (NSString*)description {
 +  return [NSString stringWithFormat:@"<%@ | '%@' | %lu bytes>", [self class], self.mimeType, (unsigned long)_data.length];
 +}
 +
 +@end
 +
 +@interface GCDWebServerMultiPartFile () {
 +@private
 +  NSString* _fileName;
 +  NSString* _temporaryPath;
 +}
 +@end
 +
 +@implementation GCDWebServerMultiPartFile
 +
 +@synthesize fileName=_fileName, temporaryPath=_temporaryPath;
 +
 +- (id)initWithControlName:(NSString*)name contentType:(NSString*)type fileName:(NSString*)fileName temporaryPath:(NSString*)temporaryPath {
 +  if ((self = [super initWithControlName:name contentType:type])) {
 +    _fileName = [fileName copy];
 +    _temporaryPath = [temporaryPath copy];
 +  }
 +  return self;
 +}
 +
 +- (void)dealloc {
 +  unlink([_temporaryPath fileSystemRepresentation]);
 +}
 +
 +- (NSString*)description {
 +  return [NSString stringWithFormat:@"<%@ | '%@' | '%@>'", [self class], self.mimeType, _fileName];
 +}
 +
 +@end
 +
 +@interface GCDWebServerMIMEStreamParser () {
 +@private
 +  NSData* _boundary;
 +  NSString* _defaultcontrolName;
 +  ParserState _state;
 +  NSMutableData* _data;
 +  NSMutableArray* _arguments;
 +  NSMutableArray* _files;
 +  
 +  NSString* _controlName;
 +  NSString* _fileName;
 +  NSString* _contentType;
 +  NSString* _tmpPath;
 +  int _tmpFile;
 +  GCDWebServerMIMEStreamParser* _subParser;
 +}
 +@end
 +
 +@implementation GCDWebServerMIMEStreamParser
 +
 ++ (void)initialize {
 +  if (_newlineData == nil) {
 +    _newlineData = [[NSData alloc] initWithBytes:"\r\n" length:2];
 +    GWS_DCHECK(_newlineData);
 +  }
 +  if (_newlinesData == nil) {
 +    _newlinesData = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
 +    GWS_DCHECK(_newlinesData);
 +  }
 +  if (_dashNewlineData == nil) {
 +    _dashNewlineData = [[NSData alloc] initWithBytes:"--\r\n" length:4];
 +    GWS_DCHECK(_dashNewlineData);
 +  }
 +}
 +
 +- (id)initWithBoundary:(NSString*)boundary defaultControlName:(NSString*)name arguments:(NSMutableArray*)arguments files:(NSMutableArray*)files {
 +  NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
 +  if (data == nil) {
 +    GWS_DNOT_REACHED();
 +    return nil;
 +  }
 +  if ((self = [super init])) {
 +    _boundary = data;
 +    _defaultcontrolName = name;
 +    _arguments = arguments;
 +    _files = files;
 +    _data = [[NSMutableData alloc] initWithCapacity:kMultiPartBufferSize];
 +    _state = kParserState_Start;
 +  }
 +  return self;
 +}
 +
 +- (void)dealloc {
 +  if (_tmpFile > 0) {
 +    close(_tmpFile);
 +    unlink([_tmpPath fileSystemRepresentation]);
 +  }
 +}
 +
 +// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
 +- (BOOL)_parseData {
 +  BOOL success = YES;
 +  
 +  if (_state == kParserState_Headers) {
 +    NSRange range = [_data rangeOfData:_newlinesData options:0 range:NSMakeRange(0, _data.length)];
 +    if (range.location != NSNotFound) {
 +      
 +      _controlName = nil;
 +      _fileName = nil;
 +      _contentType = nil;
 +      _tmpPath = nil;
 +      _subParser = nil;
 +      NSString* headers = [[NSString alloc] initWithData:[_data subdataWithRange:NSMakeRange(0, range.location)] encoding:NSUTF8StringEncoding];
 +      if (headers) {
 +        for (NSString* header in [headers componentsSeparatedByString:@"\r\n"]) {
 +          NSRange subRange = [header rangeOfString:@":"];
 +          if (subRange.location != NSNotFound) {
 +            NSString* name = [header substringToIndex:subRange.location];
 +            NSString* value = [[header substringFromIndex:(subRange.location + subRange.length)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
 +            if ([name caseInsensitiveCompare:@"Content-Type"] == NSOrderedSame) {
 +              _contentType = GCDWebServerNormalizeHeaderValue(value);
 +            } else if ([name caseInsensitiveCompare:@"Content-Disposition"] == NSOrderedSame) {
 +              NSString* contentDisposition = GCDWebServerNormalizeHeaderValue(value);
 +              if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"form-data"]) {
 +                _controlName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"name");
 +                _fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
 +              } else if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"file"]) {
 +                _controlName = _defaultcontrolName;
 +                _fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
 +              }
 +            }
 +          } else {
 +            GWS_DNOT_REACHED();
 +          }
 +        }
 +        if (_contentType == nil) {
 +          _contentType = @"text/plain";
 +        }
 +      } else {
 +        GWS_LOG_ERROR(@"Failed decoding headers in part of 'multipart/form-data'");
 +        GWS_DNOT_REACHED();
 +      }
 +      if (_controlName) {
 +        if ([GCDWebServerTruncateHeaderValue(_contentType) isEqualToString:@"multipart/mixed"]) {
 +          NSString* boundary = GCDWebServerExtractHeaderValueParameter(_contentType, @"boundary");
 +          _subParser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:_controlName arguments:_arguments files:_files];
 +          if (_subParser == nil) {
 +            GWS_DNOT_REACHED();
 +            success = NO;
 +          }
 +        } else if (_fileName) {
 +          NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
 +          _tmpFile = open([path fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 +          if (_tmpFile > 0) {
 +            _tmpPath = [path copy];
 +          } else {
 +            GWS_DNOT_REACHED();
 +            success = NO;
 +          }
 +        }
 +      } else {
 +        GWS_DNOT_REACHED();
 +        success = NO;
 +      }
 +      
 +      [_data replaceBytesInRange:NSMakeRange(0, range.location + range.length) withBytes:NULL length:0];
 +      _state = kParserState_Content;
 +    }
 +  }
 +  
 +  if ((_state == kParserState_Start) || (_state == kParserState_Content)) {
 +    NSRange range = [_data rangeOfData:_boundary options:0 range:NSMakeRange(0, _data.length)];
 +    if (range.location != NSNotFound) {
 +      NSRange subRange = NSMakeRange(range.location + range.length, _data.length - range.location - range.length);
 +      NSRange subRange1 = [_data rangeOfData:_newlineData options:NSDataSearchAnchored range:subRange];
 +      NSRange subRange2 = [_data rangeOfData:_dashNewlineData options:NSDataSearchAnchored range:subRange];
 +      if ((subRange1.location != NSNotFound) || (subRange2.location != NSNotFound)) {
 +        
 +        if (_state == kParserState_Content) {
 +          const void* dataBytes = _data.bytes;
 +          NSUInteger dataLength = range.location - 2;
 +          if (_subParser) {
 +            if (![_subParser appendBytes:dataBytes length:(dataLength + 2)] || ![_subParser isAtEnd]) {
 +              GWS_DNOT_REACHED();
 +              success = NO;
 +            }
 +            _subParser = nil;
 +          } else if (_tmpPath) {
 +            ssize_t result = write(_tmpFile, dataBytes, dataLength);
 +            if (result == (ssize_t)dataLength) {
 +              if (close(_tmpFile) == 0) {
 +                _tmpFile = 0;
 +                GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
 +                [_files addObject:file];
 +              } else {
 +                GWS_DNOT_REACHED();
 +                success = NO;
 +              }
 +            } else {
 +              GWS_DNOT_REACHED();
 +              success = NO;
 +            }
 +            _tmpPath = nil;
 +          } else {
 +            NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
 +            GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data];
 +            [_arguments addObject:argument];
 +          }
 +        }
 +        
 +        if (subRange1.location != NSNotFound) {
 +          [_data replaceBytesInRange:NSMakeRange(0, subRange1.location + subRange1.length) withBytes:NULL length:0];
 +          _state = kParserState_Headers;
 +          success = [self _parseData];
 +        } else {
 +          _state = kParserState_End;
 +        }
 +      }
 +    } else {
 +      NSUInteger margin = 2 * _boundary.length;
 +      if (_data.length > margin) {
 +        NSUInteger length = _data.length - margin;
 +        if (_subParser) {
 +          if ([_subParser appendBytes:_data.bytes length:length]) {
 +            [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
 +          } else {
 +            GWS_DNOT_REACHED();
 +            success = NO;
 +          }
 +        } else if (_tmpPath) {
 +          ssize_t result = write(_tmpFile, _data.bytes, length);
 +          if (result == (ssize_t)length) {
 +            [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
 +          } else {
 +            GWS_DNOT_REACHED();
 +            success = NO;
 +          }
 +        }
 +      }
 +    }
 +  }
 +  
 +  return success;
 +}
 +
 +- (BOOL)appendBytes:(const void*)bytes length:(NSUInteger)length {
 +  [_data appendBytes:bytes length:length];
 +  return [self _parseData];
 +}
 +
 +- (BOOL)isAtEnd {
 +  return (_state == kParserState_End);
 +}
 +
 +@end
 +
 +@interface GCDWebServerMultiPartFormRequest () {
 +@private
 +  GCDWebServerMIMEStreamParser* _parser;
 +  NSMutableArray* _arguments;
 +  NSMutableArray* _files;
 +}
 +@end
 +
 +@implementation GCDWebServerMultiPartFormRequest
 +
 +@synthesize arguments=_arguments, files=_files;
 +
 ++ (NSString*)mimeType {
 +  return @"multipart/form-data";
 +}
 +
 +- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
 +  if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
 +    _arguments = [[NSMutableArray alloc] init];
 +    _files = [[NSMutableArray alloc] init];
 +  }
 +  return self;
 +}
 +
 +- (BOOL)open:(NSError**)error {
 +  NSString* boundary = GCDWebServerExtractHeaderValueParameter(self.contentType, @"boundary");
 +  _parser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:nil arguments:_arguments files:_files];
 +  if (_parser == nil) {
-     *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
++    if (error) {
++      *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed starting to parse multipart form data"}];
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (BOOL)writeData:(NSData*)data error:(NSError**)error {
 +  if (![_parser appendBytes:data.bytes length:data.length]) {
-     *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
++    if (error) {
++      *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed continuing to parse multipart form data"}];
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (BOOL)close:(NSError**)error {
 +  BOOL atEnd = [_parser isAtEnd];
 +  _parser = nil;
 +  if (!atEnd) {
-     *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
++    if (error) {
++      *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Failed finishing to parse multipart form data"}];
++    }
 +    return NO;
 +  }
 +  return YES;
 +}
 +
 +- (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name {
 +  for (GCDWebServerMultiPartArgument* argument in _arguments) {
 +    if ([argument.controlName isEqualToString:name]) {
 +      return argument;
 +    }
 +  }
 +  return nil;
 +}
 +
 +- (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name {
 +  for (GCDWebServerMultiPartFile* file in _files) {
 +    if ([file.controlName isEqualToString:name]) {
 +      return file;
 +    }
 +  }
 +  return nil;
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithString:[super description]];
 +  if (_arguments.count) {
 +    [description appendString:@"\n"];
 +    for (GCDWebServerMultiPartArgument* argument in _arguments) {
 +      [description appendFormat:@"\n%@ (%@)\n", argument.controlName, argument.contentType];
 +      [description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)];
 +    }
 +  }
 +  if (_files.count) {
 +    [description appendString:@"\n"];
 +    for (GCDWebServerMultiPartFile* file in _files) {
 +      [description appendFormat:@"\n%@ (%@): %@\n{%@}", file.controlName, file.contentType, file.fileName, file.temporaryPath];
 +    }
 +  }
 +  return description;
 +}
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
index e36eac3,0000000..9735380
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
@@@ -1,51 -1,0 +1,51 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerDataRequest.h"
 +
 +/**
 + *  The GCDWebServerURLEncodedFormRequest subclass of GCDWebServerRequest
 + *  parses the body of the HTTP request as a URL encoded form using
 + *  GCDWebServerParseURLEncodedForm().
 + */
 +@interface GCDWebServerURLEncodedFormRequest : GCDWebServerDataRequest
 +
 +/**
 + *  Returns the unescaped control names and values for the URL encoded form.
 + *
 + *  The text encoding used to interpret the data is extracted from the
 + *  "Content-Type" header or defaults to UTF-8.
 + */
 +@property(nonatomic, readonly) NSDictionary* arguments;
 +
 +/**
 + *  Returns the MIME type for URL encoded forms
 + *  i.e. "application/x-www-form-urlencoded".
 + */
 ++ (NSString*)mimeType;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
index f210fa0,0000000..2c5fcc5
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m
@@@ -1,70 -1,0 +1,70 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerPrivate.h"
 +
 +@interface GCDWebServerURLEncodedFormRequest () {
 +@private
 +  NSDictionary* _arguments;
 +}
 +@end
 +
 +@implementation GCDWebServerURLEncodedFormRequest
 +
 +@synthesize arguments=_arguments;
 +
 ++ (NSString*)mimeType {
 +  return @"application/x-www-form-urlencoded";
 +}
 +
 +- (BOOL)close:(NSError**)error {
 +  if (![super close:error]) {
 +    return NO;
 +  }
 +  
 +  NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
 +  NSString* string = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
 +  _arguments = GCDWebServerParseURLEncodedForm(string);
 +  GWS_DCHECK(_arguments);
 +  
 +  return YES;
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithString:[super description]];
 +  [description appendString:@"\n"];
 +  for (NSString* argument in [[_arguments allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
 +    [description appendFormat:@"\n%@ = %@", argument, [_arguments objectForKey:argument]];
 +  }
 +  return description;
 +}
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
index b0c6493,0000000..6e06cd8
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
@@@ -1,108 -1,0 +1,108 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerResponse.h"
 +
 +/**
 + *  The GCDWebServerDataResponse subclass of GCDWebServerResponse reads the body
 + *  of the HTTP response from memory.
 + */
 +@interface GCDWebServerDataResponse : GCDWebServerResponse
 +
 +/**
 + *  Creates a response with data in memory and a given content type.
 + */
 ++ (instancetype)responseWithData:(NSData*)data contentType:(NSString*)type;
 +
 +/**
 + *  This method is the designated initializer for the class.
 + */
 +- (instancetype)initWithData:(NSData*)data contentType:(NSString*)type;
 +
 +@end
 +
 +@interface GCDWebServerDataResponse (Extensions)
 +
 +/**
 + *  Creates a data response from text encoded using UTF-8.
 + */
 ++ (instancetype)responseWithText:(NSString*)text;
 +
 +/**
 + *  Creates a data response from HTML encoded using UTF-8.
 + */
 ++ (instancetype)responseWithHTML:(NSString*)html;
 +
 +/**
 + *  Creates a data response from an HTML template encoded using UTF-8.
 + *  See -initWithHTMLTemplate:variables: for details.
 + */
 ++ (instancetype)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables;
 +
 +/**
 + *  Creates a data response from a serialized JSON object and the default
 + *  "application/json" content type.
 + */
 ++ (instancetype)responseWithJSONObject:(id)object;
 +
 +/**
 + *  Creates a data response from a serialized JSON object and a custom
 + *  content type.
 + */
 ++ (instancetype)responseWithJSONObject:(id)object contentType:(NSString*)type;
 +
 +/**
 + *  Initializes a data response from text encoded using UTF-8.
 + */
 +- (instancetype)initWithText:(NSString*)text;
 +
 +/**
 + *  Initializes a data response from HTML encoded using UTF-8.
 + */
 +- (instancetype)initWithHTML:(NSString*)html;
 +
 +/**
 + *  Initializes a data response from an HTML template encoded using UTF-8.
 + *
 + *  All occurences of "%variable%" within the HTML template are replaced with
 + *  their corresponding values.
 + */
 +- (instancetype)initWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables;
 +
 +/**
 + *  Initializes a data response from a serialized JSON object and the default
 + *  "application/json" content type.
 + */
 +- (instancetype)initWithJSONObject:(id)object;
 +
 +/**
 + *  Initializes a data response from a serialized JSON object and a custom
 + *  content type.
 + */
 +- (instancetype)initWithJSONObject:(id)object contentType:(NSString*)type;
 +
 +@end

http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m
index ea02799,0000000..12cd12b
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m
@@@ -1,143 -1,0 +1,143 @@@
 +/*
-  Copyright (c) 2012-2014, Pierre-Olivier Latour
++ Copyright (c) 2012-2015, 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 "GCDWebServerPrivate.h"
 +
 +@interface GCDWebServerDataResponse () {
 +@private
 +  NSData* _data;
 +  BOOL _done;
 +}
 +@end
 +
 +@implementation GCDWebServerDataResponse
 +
 ++ (instancetype)responseWithData:(NSData*)data contentType:(NSString*)type {
 +  return [[[self class] alloc] initWithData:data contentType:type];
 +}
 +
 +- (instancetype)initWithData:(NSData*)data contentType:(NSString*)type {
 +  if (data == nil) {
 +    GWS_DNOT_REACHED();
 +    return nil;
 +  }
 +  
 +  if ((self = [super init])) {
 +    _data = data;
 +    
 +    self.contentType = type;
 +    self.contentLength = data.length;
 +  }
 +  return self;
 +}
 +
 +- (NSData*)readData:(NSError**)error {
 +  NSData* data;
 +  if (_done) {
 +    data = [NSData data];
 +  } else {
 +    data = _data;
 +    _done = YES;
 +  }
 +  return data;
 +}
 +
 +- (NSString*)description {
 +  NSMutableString* description = [NSMutableString stringWithString:[super description]];
 +  [description appendString:@"\n\n"];
 +  [description appendString:GCDWebServerDescribeData(_data, self.contentType)];
 +  return description;
 +}
 +
 +@end
 +
 +@implementation GCDWebServerDataResponse (Extensions)
 +
 ++ (instancetype)responseWithText:(NSString*)text {
 +  return [[self alloc] initWithText:text];
 +}
 +
 ++ (instancetype)responseWithHTML:(NSString*)html {
 +  return [[self alloc] initWithHTML:html];
 +}
 +
 ++ (instancetype)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
 +  return [[self alloc] initWithHTMLTemplate:path variables:variables];
 +}
 +
 ++ (instancetype)responseWithJSONObject:(id)object {
 +  return [[self alloc] initWithJSONObject:object];
 +}
 +
 ++ (instancetype)responseWithJSONObject:(id)object contentType:(NSString*)type {
 +  return [[self alloc] initWithJSONObject:object contentType:type];
 +}
 +
 +- (instancetype)initWithText:(NSString*)text {
 +  NSData* data = [text dataUsingEncoding:NSUTF8StringEncoding];
 +  if (data == nil) {
 +    GWS_DNOT_REACHED();
 +    return nil;
 +  }
 +  return [self initWithData:data contentType:@"text/plain; charset=utf-8"];
 +}
 +
 +- (instancetype)initWithHTML:(NSString*)html {
 +  NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
 +  if (data == nil) {
 +    GWS_DNOT_REACHED();
 +    return nil;
 +  }
 +  return [self initWithData:data contentType:@"text/html; charset=utf-8"];
 +}
 +
 +- (instancetype)initWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
 +  NSMutableString* html = [[NSMutableString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
 +  [variables enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) {
 +    [html replaceOccurrencesOfString:[NSString stringWithFormat:@"%%%@%%", key] withString:value options:0 range:NSMakeRange(0, html.length)];
 +  }];
 +  id response = [self initWithHTML:html];
 +  return response;
 +}
 +
 +- (instancetype)initWithJSONObject:(id)object {
 +  return [self initWithJSONObject:object contentType:@"application/json"];
 +}
 +
 +- (instancetype)initWithJSONObject:(id)object contentType:(NSString*)type {
 +  NSData* data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
 +  if (data == nil) {
 +    return nil;
 +  }
 +  return [self initWithData:data contentType:type];
 +}
 +
 +@end


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