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:36 UTC
[50/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/Responses/GCDWebServerErrorResponse.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h
index 381b122,0000000..dad0114
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h
@@@ -1,81 -1,0 +1,81 @@@
+/*
- 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 "GCDWebServerDataResponse.h"
+#import "GCDWebServerHTTPStatusCodes.h"
+
+/**
+ * The GCDWebServerDataResponse subclass of GCDWebServerDataResponse generates
+ * an HTML body from an HTTP status code and an error message.
+ */
+@interface GCDWebServerErrorResponse : GCDWebServerDataResponse
+
+/**
+ * Creates a client error response with the corresponding HTTP status code.
+ */
++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3);
+
+/**
+ * Creates a server error response with the corresponding HTTP status code.
+ */
++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3);
+
+/**
+ * Creates a client error response with the corresponding HTTP status code
+ * and an underlying NSError.
+ */
++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4);
+
+/**
+ * Creates a server error response with the corresponding HTTP status code
+ * and an underlying NSError.
+ */
++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4);
+
+/**
+ * Initializes a client error response with the corresponding HTTP status code.
+ */
+- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3);
+
+/**
+ * Initializes a server error response with the corresponding HTTP status code.
+ */
+- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2,3);
+
+/**
+ * Initializes a client error response with the corresponding HTTP status code
+ * and an underlying NSError.
+ */
+- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4);
+
+/**
+ * Initializes a server error response with the corresponding HTTP status code
+ * and an underlying NSError.
+ */
+- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3,4);
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m
index c2e4422,0000000..ef6a991
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m
@@@ -1,128 -1,0 +1,128 @@@
+/*
- 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 GCDWebServerErrorResponse ()
+- (instancetype)initWithStatusCode:(NSInteger)statusCode underlyingError:(NSError*)underlyingError messageFormat:(NSString*)format arguments:(va_list)arguments;
+@end
+
+@implementation GCDWebServerErrorResponse
+
++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+ va_list arguments;
+ va_start(arguments, format);
+ GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return response;
+}
+
++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+ va_list arguments;
+ va_start(arguments, format);
+ GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return response;
+}
+
++ (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+ va_list arguments;
+ va_start(arguments, format);
+ GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return response;
+}
+
++ (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+ va_list arguments;
+ va_start(arguments, format);
+ GCDWebServerErrorResponse* response = [[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return response;
+}
+
+static inline NSString* _EscapeHTMLString(NSString* string) {
+ return [string stringByReplacingOccurrencesOfString:@"\"" withString:@"""];
+}
+
+- (instancetype)initWithStatusCode:(NSInteger)statusCode underlyingError:(NSError*)underlyingError messageFormat:(NSString*)format arguments:(va_list)arguments {
+ NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
+ NSString* title = [NSString stringWithFormat:@"HTTP Error %i", (int)statusCode];
+ NSString* error = underlyingError ? [NSString stringWithFormat:@"[%@] %@ (%li)", underlyingError.domain, _EscapeHTMLString(underlyingError.localizedDescription), (long)underlyingError.code] : @"";
+ NSString* html = [NSString stringWithFormat:@"<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"utf-8\"><title>%@</title></head><body><h1>%@: %@</h1><h3>%@</h3></body></html>",
+ title, title, _EscapeHTMLString(message), error];
+ if ((self = [self initWithHTML:html])) {
+ self.statusCode = statusCode;
+ }
+ return self;
+}
+
+- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+ va_list arguments;
+ va_start(arguments, format);
+ self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return self;
+}
+
+- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+ va_list arguments;
+ va_start(arguments, format);
+ self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return self;
+}
+
+- (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
+ va_list arguments;
+ va_start(arguments, format);
+ self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return self;
+}
+
+- (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
+ GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
+ va_list arguments;
+ va_start(arguments, format);
+ self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
+ va_end(arguments);
+ return self;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
index 19d284d,0000000..050e92f
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
@@@ -1,96 -1,0 +1,96 @@@
+/*
- 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 GCDWebServerFileResponse subclass of GCDWebServerResponse reads the body
+ * of the HTTP response from a file on disk.
+ *
+ * It will automatically set the contentType, lastModifiedDate and eTag
+ * properties of the GCDWebServerResponse according to the file extension and
+ * metadata.
+ */
+@interface GCDWebServerFileResponse : GCDWebServerResponse
+
+/**
+ * Creates a response with the contents of a file.
+ */
++ (instancetype)responseWithFile:(NSString*)path;
+
+/**
+ * Creates a response like +responseWithFile: and sets the "Content-Disposition"
+ * HTTP header for a download if the "attachment" argument is YES.
+ */
++ (instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment;
+
+/**
+ * Creates a response like +responseWithFile: but restricts the file contents
+ * to a specific byte range.
+ *
+ * See -initWithFile:byteRange: for details.
+ */
++ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range;
+
+/**
+ * Creates a response like +responseWithFile:byteRange: and sets the
+ * "Content-Disposition" HTTP header for a download if the "attachment"
+ * argument is YES.
+ */
++ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment;
+
+/**
+ * Initializes a response with the contents of a file.
+ */
+- (instancetype)initWithFile:(NSString*)path;
+
+/**
+ * Initializes a response like +responseWithFile: and sets the
+ * "Content-Disposition" HTTP header for a download if the "attachment"
+ * argument is YES.
+ */
+- (instancetype)initWithFile:(NSString*)path isAttachment:(BOOL)attachment;
+
+/**
+ * Initializes a response like -initWithFile: but restricts the file contents
+ * to a specific byte range. This range should be set to (NSUIntegerMax, 0) for
+ * the full file, (offset, length) if expressed from the beginning of the file,
+ * or (NSUIntegerMax, length) if expressed from the end of the file. The "offset"
+ * and "length" values will be automatically adjusted to be compatible with the
+ * actual size of the file.
+ *
+ * This argument would typically be set to the value of the byteRange property
+ * of the current GCDWebServerRequest.
+ */
+- (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range;
+
+/**
+ * This method is the designated initializer for the class.
+ */
+- (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m
index 2004327,0000000..a2b7c3c
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m
@@@ -1,181 -1,0 +1,187 @@@
+/*
- 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 <sys/stat.h>
+
+#import "GCDWebServerPrivate.h"
+
+#define kFileReadBufferSize (32 * 1024)
+
+@interface GCDWebServerFileResponse () {
+@private
+ NSString* _path;
+ NSUInteger _offset;
+ NSUInteger _size;
+ int _file;
+}
+@end
+
+@implementation GCDWebServerFileResponse
+
++ (instancetype)responseWithFile:(NSString*)path {
+ return [[[self class] alloc] initWithFile:path];
+}
+
++ (instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment {
+ return [[[self class] alloc] initWithFile:path isAttachment:attachment];
+}
+
++ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range {
+ return [[[self class] alloc] initWithFile:path byteRange:range];
+}
+
++ (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
+ return [[[self class] alloc] initWithFile:path byteRange:range isAttachment:attachment];
+}
+
+- (instancetype)initWithFile:(NSString*)path {
+ return [self initWithFile:path byteRange:NSMakeRange(NSUIntegerMax, 0) isAttachment:NO];
+}
+
+- (instancetype)initWithFile:(NSString*)path isAttachment:(BOOL)attachment {
+ return [self initWithFile:path byteRange:NSMakeRange(NSUIntegerMax, 0) isAttachment:attachment];
+}
+
+- (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range {
+ return [self initWithFile:path byteRange:range isAttachment:NO];
+}
+
+static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
+ return [NSDate dateWithTimeIntervalSince1970:((NSTimeInterval)t->tv_sec + (NSTimeInterval)t->tv_nsec / 1000000000.0)];
+}
+
+- (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
+ struct stat info;
+ if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) {
+ GWS_DNOT_REACHED();
+ return nil;
+ }
+#ifndef __LP64__
+ if (info.st_size >= (off_t)4294967295) { // In 32 bit mode, we can't handle files greater than 4 GiBs (don't use "NSUIntegerMax" here to avoid potential unsigned to signed conversion issues)
+ GWS_DNOT_REACHED();
+ return nil;
+ }
+#endif
+ NSUInteger fileSize = (NSUInteger)info.st_size;
+
+ BOOL hasByteRange = GCDWebServerIsValidByteRange(range);
+ if (hasByteRange) {
+ if (range.location != NSUIntegerMax) {
+ range.location = MIN(range.location, fileSize);
+ range.length = MIN(range.length, fileSize - range.location);
+ } else {
+ range.length = MIN(range.length, fileSize);
+ range.location = fileSize - range.length;
+ }
+ if (range.length == 0) {
+ return nil; // TODO: Return 416 status code and "Content-Range: bytes */{file length}" header
+ }
+ } else {
+ range.location = 0;
+ range.length = fileSize;
+ }
+
+ if ((self = [super init])) {
+ _path = [path copy];
+ _offset = range.location;
+ _size = range.length;
+ if (hasByteRange) {
+ [self setStatusCode:kGCDWebServerHTTPStatusCode_PartialContent];
+ [self setValue:[NSString stringWithFormat:@"bytes %lu-%lu/%lu", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), (unsigned long)fileSize] forAdditionalHeader:@"Content-Range"];
+ GWS_LOG_DEBUG(@"Using content bytes range [%lu-%lu] for file \"%@\"", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), path);
+ }
+
+ if (attachment) {
+ NSString* fileName = [path lastPathComponent];
+ NSData* data = [[fileName stringByReplacingOccurrencesOfString:@"\"" withString:@""] dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:YES];
+ NSString* lossyFileName = data ? [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding] : nil;
+ if (lossyFileName) {
+ NSString* value = [NSString stringWithFormat:@"attachment; filename=\"%@\"; filename*=UTF-8''%@", lossyFileName, GCDWebServerEscapeURLString(fileName)];
+ [self setValue:value forAdditionalHeader:@"Content-Disposition"];
+ } else {
+ GWS_DNOT_REACHED();
+ }
+ }
+
+ self.contentType = GCDWebServerGetMimeTypeForExtension([_path pathExtension]);
+ self.contentLength = _size;
+ self.lastModifiedDate = _NSDateFromTimeSpec(&info.st_mtimespec);
+ self.eTag = [NSString stringWithFormat:@"%llu/%li/%li", info.st_ino, info.st_mtimespec.tv_sec, info.st_mtimespec.tv_nsec];
+ }
+ return self;
+}
+
+- (BOOL)open:(NSError**)error {
+ _file = open([_path fileSystemRepresentation], O_NOFOLLOW | O_RDONLY);
+ if (_file <= 0) {
- *error = GCDWebServerMakePosixError(errno);
++ if (error) {
++ *error = GCDWebServerMakePosixError(errno);
++ }
+ return NO;
+ }
+ if (lseek(_file, _offset, SEEK_SET) != (off_t)_offset) {
- *error = GCDWebServerMakePosixError(errno);
++ if (error) {
++ *error = GCDWebServerMakePosixError(errno);
++ }
+ close(_file);
+ return NO;
+ }
+ return YES;
+}
+
+- (NSData*)readData:(NSError**)error {
+ size_t length = MIN((NSUInteger)kFileReadBufferSize, _size);
+ NSMutableData* data = [[NSMutableData alloc] initWithLength:length];
+ ssize_t result = read(_file, data.mutableBytes, length);
+ if (result < 0) {
- *error = GCDWebServerMakePosixError(errno);
++ if (error) {
++ *error = GCDWebServerMakePosixError(errno);
++ }
+ return nil;
+ }
+ if (result > 0) {
+ [data setLength:result];
+ _size -= result;
+ }
+ return data;
+}
+
+- (void)close {
+ close(_file);
+}
+
+- (NSString*)description {
+ NSMutableString* description = [NSMutableString stringWithString:[super description]];
+ [description appendFormat:@"\n\n{%@}", _path];
+ return description;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
index 4f39625,0000000..2731b7c
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
@@@ -1,78 -1,0 +1,75 @@@
+/*
- 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 GCDWebServerStreamBlock is called to stream the data for the HTTP body.
- * The block must return empty NSData when done or nil on error and set the
- * "error" argument which is guaranteed to be non-NULL.
++ * The block must return either a chunk of data, an empty NSData when done, or
++ * nil on error and set the "error" argument which is guaranteed to be non-NULL.
+ */
+typedef NSData* (^GCDWebServerStreamBlock)(NSError** error);
+
+/**
+ * The GCDWebServerAsyncStreamBlock works like the GCDWebServerStreamBlock
+ * except the streamed data can be returned at a later time allowing for
+ * truly asynchronous generation of the data.
+ *
- * The block must return empty NSData when done or nil on error and set the
- * "error" argument which is guaranteed to be non-NULL.
++ * The block must call "completionBlock" passing the new chunk of data when ready,
++ * an empty NSData when done, or nil on error and pass a NSError.
+ *
- * The block must regularly call "completionBlock" passing new streamed data.
- * Eventually it must call "completionBlock" passing an empty NSData indicating
- * the end of the stream has been reached, or pass nil and an NSError in case of
- * error.
++ * The block cannot call "completionBlock" more than once per invocation.
+ */
+typedef void (^GCDWebServerAsyncStreamBlock)(GCDWebServerBodyReaderCompletionBlock completionBlock);
+
+/**
+ * The GCDWebServerStreamedResponse subclass of GCDWebServerResponse streams
+ * the body of the HTTP response using a GCD block.
+ */
+@interface GCDWebServerStreamedResponse : GCDWebServerResponse
+
+/**
+ * Creates a response with streamed data and a given content type.
+ */
++ (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
+
+/**
+ * Creates a response with async streamed data and a given content type.
+ */
++ (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
+
+/**
+ * Initializes a response with streamed data and a given content type.
+ */
+- (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
+
+/**
+ * This method is the designated initializer for the class.
+ */
+- (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
index 7f96943,0000000..4669617
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m
@@@ -1,79 -1,0 +1,79 @@@
+/*
- 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 GCDWebServerStreamedResponse () {
+@private
+ GCDWebServerAsyncStreamBlock _block;
+}
+@end
+
+@implementation GCDWebServerStreamedResponse
+
++ (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
+ return [[[self class] alloc] initWithContentType:type streamBlock:block];
+}
+
++ (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
+ return [[[self class] alloc] initWithContentType:type asyncStreamBlock:block];
+}
+
+- (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
+ return [self initWithContentType:type asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
+
+ NSError* error = nil;
+ NSData* data = block(&error);
+ completionBlock(data, error);
+
+ }];
+}
+
+- (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
+ if ((self = [super init])) {
+ _block = [block copy];
+
+ self.contentType = type;
+ }
+ return self;
+}
+
+- (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
+ _block(block);
+}
+
+- (NSString*)description {
+ NSMutableString* description = [NSMutableString stringWithString:[super description]];
+ [description appendString:@"\n\n<STREAM>"];
+ return description;
+}
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css
index aed15e4,0000000..53b0247
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/css/index.css
@@@ -1,130 -1,0 +1,130 @@@
+/*
- 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.
+ */
+
+.row-file {
+ height: 40px;
+}
+
+.column-icon {
+ width: 40px;
+ text-align: center;
+}
+
+.column-name {
+}
+
+.column-size {
+ width: 100px;
+ text-align: right;
+}
+
+.column-move {
+ width: 40px;
+ text-align: center;
+}
+
+.column-delete {
+ width: 40px;
+ text-align: center;
+}
+
+.column-path {
+}
+
+.column-progress {
+ width: 200px;
+}
+
+.footer {
+ color: #999;
+ text-align: center;
+ font-size: 0.9em;
+}
+
+#reload {
+ float: right;
+}
+
+#create-input {
+ width: 50%;
+ height: 20px;
+}
+
+#move-input {
+ width: 80%;
+ height: 20px;
+}
+
+/* Bootstrap overrides */
+
+.btn:focus {
+ outline: none; /* FIXME: Work around for Chrome only but still draws focus ring while button pressed */
+}
+
+.btn-toolbar {
+ margin-top: 30px;
+ margin-bottom: 20px;
+}
+
+.table .progress {
+ margin-top: 0px;
+ margin-bottom: 0px;
+ height: 16px;
+}
+
+.panel-default > .panel-heading {
+ color: #555;
+}
+
+.breadcrumb {
+ background-color: transparent;
+ border-radius: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+.breadcrumb > .active {
+ color: #555;
+}
+
+.breadcrumb > li + li:before {
+ color: #999;
+}
+
+.table > tbody > tr > td {
+ vertical-align: middle;
+}
+
+.table > tbody > tr > td > p {
+ margin: 0px;
+}
+
+/* Initial state */
+
+.uploading {
+ display: none;
+}
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html
index 28d371c,0000000..1bfd28e
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/index.html
@@@ -1,196 -1,0 +1,196 @@@
+<!--
- 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.
+-->
+
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <title>%title%</title>
+ <link rel="stylesheet" href="css/bootstrap.css">
+ <link rel="stylesheet" href="css/bootstrap-theme.css">
+ <link rel="stylesheet" href="css/jquery.fileupload.css">
+ <link rel="stylesheet" href="css/index.css">
+ <!--[if lt IE 9]>
+ <script type="text/javascript" src="js/html5shiv.min.js"></script>
+ <script type="text/javascript" src="js/respond.min.js"></script>
+ <![endif]-->
+ <script type="text/javascript" src="js/jquery.min.js"></script>
+ <script type="text/javascript" src="js/jquery.ui.widget.js"></script>
+ <script type="text/javascript" src="js/jquery.jeditable.js"></script>
+ <script type="text/javascript" src="js/jquery.fileupload.js"></script>
+ <script type="text/javascript" src="js/jquery.iframe-transport.js"></script>
+ <script type="text/javascript" src="js/bootstrap.min.js"></script>
+ <script type="text/javascript" src="js/tmpl.min.js"></script>
+ <script type="text/javascript">
+ var _device = "%device%";
+ </script>
+ <script type="text/javascript" src="js/index.js"></script>
+ </head>
+ <body>
+
+ <div class="container">
+
+ <div class="page-header">
+ <h1>%header%</h1>
+ </div>
+
+ %prologue%
+
+ <div id="alerts"></div>
+
+ <div class="btn-toolbar">
- <button type="button" class="btn btn-primary fileinput-button">
++ <button type="button" class="btn btn-primary fileinput-button" id="upload-file">
+ <span class="glyphicon glyphicon-upload"></span> Upload Files…
+ <input id="fileupload" type="file" name="files[]" multiple>
+ </button>
+ <button type="button" class="btn btn-success" id="create-folder">
+ <span class="glyphicon glyphicon-folder-close"></span> Create Folder…
+ </button>
+ <button type="button" class="btn btn-default" id="reload">
+ <span class="glyphicon glyphicon-refresh"></span> Refresh
+ </button>
+ </div>
+
+ <div class="panel panel-default uploading">
+ <div class="panel-heading">File Uploads in Progress</div>
+ <table class="table table-striped"><tbody id="uploads"></tbody></table>
+ </div>
+
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <ol class="breadcrumb" id="path"></ol>
+ </div>
+ <table class="table table-striped"><tbody id="listing"></tbody></table>
+ </div>
+
+ %epilogue%
+
+ <p class="footer">%footer%</p>
+
+ </div>
+
+ <div class="modal fade" id="create-modal" tabindex="-1">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">×</button>
+ <h4 class="modal-title">Create Folder</h4>
+ </div>
+ <div class="modal-body">
+ <p>Please enter the name of the folder to be created:</p>
+ <form onsubmit="return false">
+ <input type="text" autocomplete="off" id="create-input">
+ </form>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+ <button type="button" class="btn btn-primary" id="create-confirm">Create Folder</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="modal fade" id="move-modal" tabindex="-1">
+ <div class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal">×</button>
+ <h4 class="modal-title">Move Item</h4>
+ </div>
+ <div class="modal-body">
+ <p>Please enter the new location for this item:</p>
+ <form onsubmit="return false">
+ <input type="text" autocomplete="off" id="move-input">
+ </form>
+ </div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+ <button type="button" class="btn btn-primary" id="move-confirm">Move Item</button>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <script type="text/x-tmpl" id="template-listing">
+ <tr class="row-file">
+ <td class="column-icon">
+ {% if (o.size != null) { %}
+ <button type="button" class="btn btn-default btn-xs button-download">
+ <span class="glyphicon glyphicon-download-alt"></span>
+ </button>
+ {% } else { %}
+ <button type="button" class="btn btn-default btn-xs button-open">
+ <span class="glyphicon glyphicon-folder-open"></span>
+ </button>
+ {% } %}
+ </td>
+ <td class="column-name"><p class="edit">{%=o.name%}</p></td>
+ <td class="column-size">
+ {% if (o.size != null) { %}
+ <p>{%=formatFileSize(o.size)%}</p>
+ {% } %}
+ </td>
+ <td class="column-move">
+ <button type="button" class="btn btn-default btn-xs button-move">
+ <span class="glyphicon glyphicon glyphicon-share-alt"></span>
+ </button>
+ </td>
+ <td class="column-delete">
+ <button type="button" class="btn btn-danger btn-xs button-delete">
+ <span class="glyphicon glyphicon-trash"></span>
+ </button>
+ </td>
+ </tr>
+ </script>
+
+ <script type="text/x-tmpl" id="template-uploads">
+ <tr class="row-file">
+ <td class="column-icon">
+ <button type="button" class="btn btn-warning btn-xs button-cancel">
+ <span class="glyphicon glyphicon-ban-circle"></span>
+ </button>
+ </td>
+ <td class="column-path"><p>{%=o.path%}</p></td>
+ <td class="column-progress">
+ <div class="progress">
+ <div class="progress-bar" id="progress-bar"></div>
+ </div>
+ </ts>
+ </tr>
+ </script>
+
+ <script type="text/x-tmpl" id="template-alert">
+ <div class="alert alert-{%=o.level%} alert-dismissable">
+ <button type="button" class="close" data-dismiss="alert">×</button>
+ <strong>{%=o.title%}</strong>{%=o.description%}
+ </div>
+ </script>
+
+ </body>
+</html>
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js
index 5bd9218,0000000..012926d
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.bundle/js/index.js
@@@ -1,305 -1,0 +1,316 @@@
+/*
- 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.
+ */
+
+var ENTER_KEYCODE = 13;
+
+var _path = null;
+var _pendingReloads = [];
+var _reloadingDisabled = 0;
+
+function formatFileSize(bytes) {
+ if (bytes >= 1000000000) {
+ return (bytes / 1000000000).toFixed(2) + ' GB';
+ }
+ if (bytes >= 1000000) {
+ return (bytes / 1000000).toFixed(2) + ' MB';
+ }
+ return (bytes / 1000).toFixed(2) + ' KB';
+}
+
+function _showError(message, textStatus, errorThrown) {
+ $("#alerts").prepend(tmpl("template-alert", {
+ level: "danger",
+ title: (errorThrown != "" ? errorThrown : textStatus) + ": ",
+ description: message
+ }));
+}
+
+function _disableReloads() {
+ _reloadingDisabled += 1;
+}
+
+function _enableReloads() {
+ _reloadingDisabled -= 1;
+
+ if (_pendingReloads.length > 0) {
+ _reload(_pendingReloads.shift());
+ }
+}
+
+function _reload(path) {
+ if (_reloadingDisabled) {
+ if ($.inArray(path, _pendingReloads) < 0) {
+ _pendingReloads.push(path);
+ }
+ return;
+ }
+
+ _disableReloads();
+ $.ajax({
+ url: 'list',
+ type: 'GET',
+ data: {path: path},
+ dataType: 'json'
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ _showError("Failed retrieving contents of \"" + path + "\"", textStatus, errorThrown);
+ }).done(function(data, textStatus, jqXHR) {
+ var scrollPosition = $(document).scrollTop();
+
+ if (path != _path) {
+ $("#path").empty();
+ if (path == "/") {
+ $("#path").append('<li class="active">' + _device + '</li>');
+ } else {
+ $("#path").append('<li data-path="/"><a>' + _device + '</a></li>');
+ var components = path.split("/").slice(1, -1);
+ for (var i = 0; i < components.length - 1; ++i) {
+ var subpath = "/" + components.slice(0, i + 1).join("/") + "/";
+ $("#path").append('<li data-path="' + subpath + '"><a>' + components[i] + '</a></li>');
+ }
+ $("#path > li").click(function(event) {
+ _reload($(this).data("path"));
+ event.preventDefault();
+ });
+ $("#path").append('<li class="active">' + components[components.length - 1] + '</li>');
+ }
+ _path = path;
+ }
+
+ $("#listing").empty();
+ for (var i = 0, file; file = data[i]; ++i) {
+ $(tmpl("template-listing", file)).data(file).appendTo("#listing");
+ }
+
+ $(".edit").editable(function(value, settings) {
+ var name = $(this).parent().parent().data("name");
+ if (value != name) {
+ var path = $(this).parent().parent().data("path");
+ $.ajax({
+ url: 'move',
+ type: 'POST',
+ data: {oldPath: path, newPath: _path + value},
+ dataType: 'json'
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ _showError("Failed moving \"" + path + "\" to \"" + _path + value + "\"", textStatus, errorThrown);
+ }).always(function() {
+ _reload(_path);
+ });
+ }
+ return value;
+ }, {
+ onedit: function(settings, original) {
+ _disableReloads();
+ },
+ onsubmit: function(settings, original) {
+ _enableReloads();
+ },
+ onreset: function(settings, original) {
+ _enableReloads();
+ },
+ tooltip: 'Click to rename...'
+ });
+
+ $(".button-download").click(function(event) {
+ var path = $(this).parent().parent().data("path");
+ setTimeout(function() {
+ window.location = "download?path=" + encodeURIComponent(path);
+ }, 0);
+ });
+
+ $(".button-open").click(function(event) {
+ var path = $(this).parent().parent().data("path");
+ _reload(path);
+ });
+
+ $(".button-move").click(function(event) {
+ var path = $(this).parent().parent().data("path");
+ if (path[path.length - 1] == "/") {
+ path = path.slice(0, path.length - 1);
+ }
+ $("#move-input").data("path", path);
+ $("#move-input").val(path);
+ $("#move-modal").modal("show");
+ });
+
+ $(".button-delete").click(function(event) {
+ var path = $(this).parent().parent().data("path");
+ $.ajax({
+ url: 'delete',
+ type: 'POST',
+ data: {path: path},
+ dataType: 'json'
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ _showError("Failed deleting \"" + path + "\"", textStatus, errorThrown);
+ }).always(function() {
+ _reload(_path);
+ });
+ });
+
+ $(document).scrollTop(scrollPosition);
+ }).always(function() {
+ _enableReloads();
+ });
+}
+
+$(document).ready(function() {
+
++ // Workaround Firefox and IE not showing file selection dialog when clicking on "upload-file" <button>
++ // Making it a <div> instead also works but then it the button doesn't work anymore with tab selection or accessibility
++ $("#upload-file").click(function(event) {
++ $("#fileupload").click();
++ });
++
++ // Prevent event bubbling when using workaround above
++ $("#fileupload").click(function(event) {
++ event.stopPropagation();
++ });
++
+ $("#fileupload").fileupload({
+ dropZone: $(document),
+ pasteZone: null,
+ autoUpload: true,
+ sequentialUploads: true,
+ // limitConcurrentUploads: 2,
+ // forceIframeTransport: true,
+
+ url: 'upload',
+ type: 'POST',
+ dataType: 'json',
+
+ start: function(e) {
+ $(".uploading").show();
+ },
+
+ stop: function(e) {
+ $(".uploading").hide();
+ },
+
+ add: function(e, data) {
+ var file = data.files[0];
+ data.formData = {
+ path: _path
+ };
+ data.context = $(tmpl("template-uploads", {
+ path: _path + file.name
+ })).appendTo("#uploads");
+ var jqXHR = data.submit();
+ data.context.find("button").click(function(event) {
+ jqXHR.abort();
+ });
+ },
+
+ progress: function(e, data) {
+ var progress = parseInt(data.loaded / data.total * 100, 10);
+ data.context.find(".progress-bar").css("width", progress + "%");
+ },
+
+ done: function(e, data) {
+ _reload(_path);
+ },
+
+ fail: function(e, data) {
+ var file = data.files[0];
+ if (data.errorThrown != "abort") {
+ _showError("Failed uploading \"" + file.name + "\" to \"" + _path + "\"", data.textStatus, data.errorThrown);
+ }
+ },
+
+ always: function(e, data) {
+ data.context.remove();
+ },
+
+ });
+
+ $("#create-input").keypress(function(event) {
+ if (event.keyCode == ENTER_KEYCODE) {
+ $("#create-confirm").click();
+ };
+ });
+
+ $("#create-modal").on("shown.bs.modal", function(event) {
+ $("#create-input").focus();
+ $("#create-input").select();
+ });
+
+ $("#create-folder").click(function(event) {
+ $("#create-input").val("Untitled folder");
+ $("#create-modal").modal("show");
+ });
+
+ $("#create-confirm").click(function(event) {
+ $("#create-modal").modal("hide");
+ var name = $("#create-input").val();
+ if (name != "") {
+ $.ajax({
+ url: 'create',
+ type: 'POST',
+ data: {path: _path + name},
+ dataType: 'json'
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ _showError("Failed creating folder \"" + name + "\" in \"" + _path + "\"", textStatus, errorThrown);
+ }).always(function() {
+ _reload(_path);
+ });
+ }
+ });
+
+ $("#move-input").keypress(function(event) {
+ if (event.keyCode == ENTER_KEYCODE) {
+ $("#move-confirm").click();
+ };
+ });
+
+ $("#move-modal").on("shown.bs.modal", function(event) {
+ $("#move-input").focus();
+ $("#move-input").select();
+ })
+
+ $("#move-confirm").click(function(event) {
+ $("#move-modal").modal("hide");
+ var oldPath = $("#move-input").data("path");
+ var newPath = $("#move-input").val();
+ if ((newPath != "") && (newPath[0] == "/") && (newPath != oldPath)) {
+ $.ajax({
+ url: 'move',
+ type: 'POST',
+ data: {oldPath: oldPath, newPath: newPath},
+ dataType: 'json'
+ }).fail(function(jqXHR, textStatus, errorThrown) {
+ _showError("Failed moving \"" + oldPath + "\" to \"" + newPath + "\"", textStatus, errorThrown);
+ }).always(function() {
+ _reload(_path);
+ });
+ }
+ });
+
+ $("#reload").click(function(event) {
+ _reload(_path);
+ });
+
+ _reload("/");
+
+});
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h
index 02ff30d,0000000..d2c92e9
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.h
@@@ -1,197 -1,0 +1,197 @@@
+/*
- 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 "GCDWebServer.h"
+
+@class GCDWebUploader;
+
+/**
+ * Delegate methods for GCDWebUploader.
+ *
+ * @warning These methods are always called on the main thread in a serialized way.
+ */
+@protocol GCDWebUploaderDelegate <GCDWebServerDelegate>
+@optional
+
+/**
+ * This method is called whenever a file has been downloaded.
+ */
+- (void)webUploader:(GCDWebUploader*)uploader didDownloadFileAtPath:(NSString*)path;
+
+/**
+ * This method is called whenever a file has been uploaded.
+ */
+- (void)webUploader:(GCDWebUploader*)uploader didUploadFileAtPath:(NSString*)path;
+
+/**
+ * This method is called whenever a file or directory has been moved.
+ */
+- (void)webUploader:(GCDWebUploader*)uploader didMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath;
+
+/**
+ * This method is called whenever a file or directory has been deleted.
+ */
+- (void)webUploader:(GCDWebUploader*)uploader didDeleteItemAtPath:(NSString*)path;
+
+/**
+ * This method is called whenever a directory has been created.
+ */
+- (void)webUploader:(GCDWebUploader*)uploader didCreateDirectoryAtPath:(NSString*)path;
+
+@end
+
+/**
+ * The GCDWebUploader subclass of GCDWebServer implements an HTML 5 web browser
+ * interface for uploading or downloading files, and moving or deleting files
+ * or directories.
+ *
+ * See the README.md file for more information about the features of GCDWebUploader.
+ *
+ * @warning For GCDWebUploader to work, "GCDWebUploader.bundle" must be added
+ * to the resources of the Xcode target.
+ */
+@interface GCDWebUploader : GCDWebServer
+
+/**
+ * Returns the upload directory as specified when the uploader was initialized.
+ */
+@property(nonatomic, readonly) NSString* uploadDirectory;
+
+/**
+ * Sets the delegate for the uploader.
+ */
+@property(nonatomic, assign) id<GCDWebUploaderDelegate> delegate;
+
+/**
+ * Sets which files are allowed to be operated on depending on their extension.
+ *
+ * The default value is nil i.e. all file extensions are allowed.
+ */
+@property(nonatomic, copy) NSArray* allowedFileExtensions;
+
+/**
+ * Sets if files and directories whose name start with a period are allowed to
+ * be operated on.
+ *
+ * The default value is NO.
+ */
+@property(nonatomic) BOOL allowHiddenItems;
+
+/**
+ * Sets the title for the uploader web interface.
+ *
+ * The default value is the application name.
+ *
+ * @warning Any reserved HTML characters in the string value for this property
+ * must have been replaced by character entities e.g. "&" becomes "&".
+ */
+@property(nonatomic, copy) NSString* title;
+
+/**
+ * Sets the header for the uploader web interface.
+ *
+ * The default value is the same as the title property.
+ *
+ * @warning Any reserved HTML characters in the string value for this property
+ * must have been replaced by character entities e.g. "&" becomes "&".
+ */
+@property(nonatomic, copy) NSString* header;
+
+/**
+ * Sets the prologue for the uploader web interface.
+ *
+ * The default value is a short help text.
+ *
+ * @warning The string value for this property must be raw HTML
+ * e.g. "<p>Some text</p>"
+ */
+@property(nonatomic, copy) NSString* prologue;
+
+/**
+ * Sets the epilogue for the uploader web interface.
+ *
+ * The default value is nil i.e. no epilogue.
+ *
+ * @warning The string value for this property must be raw HTML
+ * e.g. "<p>Some text</p>"
+ */
+@property(nonatomic, copy) NSString* epilogue;
+
+/**
+ * Sets the footer for the uploader web interface.
+ *
+ * The default value is the application name and version.
+ *
+ * @warning Any reserved HTML characters in the string value for this property
+ * must have been replaced by character entities e.g. "&" becomes "&".
+ */
+@property(nonatomic, copy) NSString* footer;
+
+/**
+ * This method is the designated initializer for the class.
+ */
+- (instancetype)initWithUploadDirectory:(NSString*)path;
+
+@end
+
+/**
+ * Hooks to customize the behavior of GCDWebUploader.
+ *
+ * @warning These methods can be called on any GCD thread.
+ */
+@interface GCDWebUploader (Subclassing)
+
+/**
+ * This method is called to check if a file upload is allowed to complete.
+ * The uploaded file is available for inspection at "tempPath".
+ *
+ * The default implementation returns YES.
+ */
+- (BOOL)shouldUploadFileAtPath:(NSString*)path withTemporaryFile:(NSString*)tempPath;
+
+/**
+ * This method is called to check if a file or directory is allowed to be moved.
+ *
+ * The default implementation returns YES.
+ */
+- (BOOL)shouldMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath;
+
+/**
+ * This method is called to check if a file or directory is allowed to be deleted.
+ *
+ * The default implementation returns YES.
+ */
+- (BOOL)shouldDeleteItemAtPath:(NSString*)path;
+
+/**
+ * This method is called to check if a directory is allowed to be created.
+ *
+ * The default implementation returns YES.
+ */
+- (BOOL)shouldCreateDirectoryAtPath:(NSString*)path;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugins/blob/36f1a43e/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m
----------------------------------------------------------------------
diff --cc local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m
index d88a45a,0000000..9bb4453
mode 100644,000000..100644
--- a/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m
+++ b/local-webserver/src/ios/GCDWebServer/GCDWebUploader/GCDWebUploader.m
@@@ -1,417 -1,0 +1,419 @@@
+/*
- 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 GCDWebUploader requires ARC
+#endif
+
+#import <TargetConditionals.h>
+#if TARGET_OS_IPHONE
+#import <UIKit/UIKit.h>
+#else
+#import <SystemConfiguration/SystemConfiguration.h>
+#endif
+
+#import "GCDWebUploader.h"
+
+#import "GCDWebServerDataRequest.h"
+#import "GCDWebServerMultiPartFormRequest.h"
+#import "GCDWebServerURLEncodedFormRequest.h"
+
+#import "GCDWebServerDataResponse.h"
+#import "GCDWebServerErrorResponse.h"
+#import "GCDWebServerFileResponse.h"
+
+@interface GCDWebUploader () {
+@private
+ NSString* _uploadDirectory;
+ NSArray* _allowedExtensions;
+ BOOL _allowHidden;
+ NSString* _title;
+ NSString* _header;
+ NSString* _prologue;
+ NSString* _epilogue;
+ NSString* _footer;
+}
+@end
+
+@implementation GCDWebUploader (Methods)
+
+// Must match implementation in GCDWebDAVServer
+- (BOOL)_checkSandboxedPath:(NSString*)path {
+ return [[path stringByStandardizingPath] hasPrefix:_uploadDirectory];
+}
+
+- (BOOL)_checkFileExtension:(NSString*)fileName {
+ if (_allowedExtensions && ![_allowedExtensions containsObject:[[fileName pathExtension] lowercaseString]]) {
+ return NO;
+ }
+ return YES;
+}
+
+- (NSString*) _uniquePathForPath:(NSString*)path {
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
+ NSString* directory = [path stringByDeletingLastPathComponent];
+ NSString* file = [path lastPathComponent];
+ NSString* base = [file stringByDeletingPathExtension];
+ NSString* extension = [file pathExtension];
+ int retries = 0;
+ do {
+ if (extension.length) {
+ path = [directory stringByAppendingPathComponent:[[base stringByAppendingFormat:@" (%i)", ++retries] stringByAppendingPathExtension:extension]];
+ } else {
+ path = [directory stringByAppendingPathComponent:[base stringByAppendingFormat:@" (%i)", ++retries]];
+ }
+ } while ([[NSFileManager defaultManager] fileExistsAtPath:path]);
+ }
+ return path;
+}
+
+- (GCDWebServerResponse*)listDirectory:(GCDWebServerRequest*)request {
+ NSString* relativePath = [[request query] objectForKey:@"path"];
+ NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
+ BOOL isDirectory = NO;
+ if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
+ }
+ if (!isDirectory) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"\"%@\" is not a directory", relativePath];
+ }
+
+ NSString* directoryName = [absolutePath lastPathComponent];
+ if (!_allowHidden && [directoryName hasPrefix:@"."]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Listing directory name \"%@\" is not allowed", directoryName];
+ }
+
+ NSError* error = nil;
+ NSArray* contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:absolutePath error:&error];
+ if (contents == nil) {
+ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed listing directory \"%@\"", relativePath];
+ }
+
+ NSMutableArray* array = [NSMutableArray array];
+ for (NSString* item in [contents sortedArrayUsingSelector:@selector(localizedStandardCompare:)]) {
+ if (_allowHidden || ![item hasPrefix:@"."]) {
+ NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[absolutePath stringByAppendingPathComponent:item] error:NULL];
+ NSString* type = [attributes objectForKey:NSFileType];
+ if ([type isEqualToString:NSFileTypeRegular] && [self _checkFileExtension:item]) {
+ [array addObject:@{
+ @"path": [relativePath stringByAppendingPathComponent:item],
+ @"name": item,
+ @"size": [attributes objectForKey:NSFileSize]
+ }];
+ } else if ([type isEqualToString:NSFileTypeDirectory]) {
+ [array addObject:@{
+ @"path": [[relativePath stringByAppendingPathComponent:item] stringByAppendingString:@"/"],
+ @"name": item
+ }];
+ }
+ }
+ }
+ return [GCDWebServerDataResponse responseWithJSONObject:array];
+}
+
+- (GCDWebServerResponse*)downloadFile:(GCDWebServerRequest*)request {
+ NSString* relativePath = [[request query] objectForKey:@"path"];
+ NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
+ BOOL isDirectory = NO;
+ if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
+ }
+ if (isDirectory) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"\"%@\" is a directory", relativePath];
+ }
+
+ NSString* fileName = [absolutePath lastPathComponent];
+ if (([fileName hasPrefix:@"."] && !_allowHidden) || ![self _checkFileExtension:fileName]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Downlading file name \"%@\" is not allowed", fileName];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(webUploader:didDownloadFileAtPath: )]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate webUploader:self didDownloadFileAtPath:absolutePath];
+ });
+ }
+ return [GCDWebServerFileResponse responseWithFile:absolutePath isAttachment:YES];
+}
+
+- (GCDWebServerResponse*)uploadFile:(GCDWebServerMultiPartFormRequest*)request {
+ NSRange range = [[request.headers objectForKey:@"Accept"] rangeOfString:@"application/json" options:NSCaseInsensitiveSearch];
+ NSString* contentType = (range.location != NSNotFound ? @"application/json" : @"text/plain; charset=utf-8"); // Required when using iFrame transport (see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup)
+
+ GCDWebServerMultiPartFile* file = [request firstFileForControlName:@"files[]"];
+ if ((!_allowHidden && [file.fileName hasPrefix:@"."]) || ![self _checkFileExtension:file.fileName]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploaded file name \"%@\" is not allowed", file.fileName];
+ }
+ NSString* relativePath = [[request firstArgumentForControlName:@"path"] string];
+ NSString* absolutePath = [self _uniquePathForPath:[[_uploadDirectory stringByAppendingPathComponent:relativePath] stringByAppendingPathComponent:file.fileName]];
+ if (![self _checkSandboxedPath:absolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
+ }
+
+ if (![self shouldUploadFileAtPath:absolutePath withTemporaryFile:file.temporaryPath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Uploading file \"%@\" to \"%@\" is not permitted", file.fileName, relativePath];
+ }
+
+ NSError* error = nil;
+ if (![[NSFileManager defaultManager] moveItemAtPath:file.temporaryPath toPath:absolutePath error:&error]) {
+ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving uploaded file to \"%@\"", relativePath];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(webUploader:didUploadFileAtPath:)]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate webUploader:self didUploadFileAtPath:absolutePath];
+ });
+ }
+ return [GCDWebServerDataResponse responseWithJSONObject:@{} contentType:contentType];
+}
+
+- (GCDWebServerResponse*)moveItem:(GCDWebServerURLEncodedFormRequest*)request {
+ NSString* oldRelativePath = [request.arguments objectForKey:@"oldPath"];
+ NSString* oldAbsolutePath = [_uploadDirectory stringByAppendingPathComponent:oldRelativePath];
+ BOOL isDirectory = NO;
+ if (![self _checkSandboxedPath:oldAbsolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:oldAbsolutePath isDirectory:&isDirectory]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", oldRelativePath];
+ }
+
+ NSString* newRelativePath = [request.arguments objectForKey:@"newPath"];
+ NSString* newAbsolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:newRelativePath]];
+ if (![self _checkSandboxedPath:newAbsolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", newRelativePath];
+ }
+
+ NSString* itemName = [newAbsolutePath lastPathComponent];
+ if ((!_allowHidden && [itemName hasPrefix:@"."]) || (!isDirectory && ![self _checkFileExtension:itemName])) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Moving to item name \"%@\" is not allowed", itemName];
+ }
+
+ if (![self shouldMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Moving \"%@\" to \"%@\" is not permitted", oldRelativePath, newRelativePath];
+ }
+
+ NSError* error = nil;
+ if (![[NSFileManager defaultManager] moveItemAtPath:oldAbsolutePath toPath:newAbsolutePath error:&error]) {
+ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed moving \"%@\" to \"%@\"", oldRelativePath, newRelativePath];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(webUploader:didMoveItemFromPath:toPath:)]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate webUploader:self didMoveItemFromPath:oldAbsolutePath toPath:newAbsolutePath];
+ });
+ }
+ return [GCDWebServerDataResponse responseWithJSONObject:@{}];
+}
+
+- (GCDWebServerResponse*)deleteItem:(GCDWebServerURLEncodedFormRequest*)request {
+ NSString* relativePath = [request.arguments objectForKey:@"path"];
+ NSString* absolutePath = [_uploadDirectory stringByAppendingPathComponent:relativePath];
+ BOOL isDirectory = NO;
+ if (![self _checkSandboxedPath:absolutePath] || ![[NSFileManager defaultManager] fileExistsAtPath:absolutePath isDirectory:&isDirectory]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
+ }
+
+ NSString* itemName = [absolutePath lastPathComponent];
+ if (([itemName hasPrefix:@"."] && !_allowHidden) || (!isDirectory && ![self _checkFileExtension:itemName])) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting item name \"%@\" is not allowed", itemName];
+ }
+
+ if (![self shouldDeleteItemAtPath:absolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Deleting \"%@\" is not permitted", relativePath];
+ }
+
+ NSError* error = nil;
+ if (![[NSFileManager defaultManager] removeItemAtPath:absolutePath error:&error]) {
+ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed deleting \"%@\"", relativePath];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(webUploader:didDeleteItemAtPath:)]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate webUploader:self didDeleteItemAtPath:absolutePath];
+ });
+ }
+ return [GCDWebServerDataResponse responseWithJSONObject:@{}];
+}
+
+- (GCDWebServerResponse*)createDirectory:(GCDWebServerURLEncodedFormRequest*)request {
+ NSString* relativePath = [request.arguments objectForKey:@"path"];
+ NSString* absolutePath = [self _uniquePathForPath:[_uploadDirectory stringByAppendingPathComponent:relativePath]];
+ if (![self _checkSandboxedPath:absolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_NotFound message:@"\"%@\" does not exist", relativePath];
+ }
+
+ NSString* directoryName = [absolutePath lastPathComponent];
+ if (!_allowHidden && [directoryName hasPrefix:@"."]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory name \"%@\" is not allowed", directoryName];
+ }
+
+ if (![self shouldCreateDirectoryAtPath:absolutePath]) {
+ return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Creating directory \"%@\" is not permitted", relativePath];
+ }
+
+ NSError* error = nil;
+ if (![[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:NO attributes:nil error:&error]) {
+ return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed creating directory \"%@\"", relativePath];
+ }
+
+ if ([self.delegate respondsToSelector:@selector(webUploader:didCreateDirectoryAtPath:)]) {
+ dispatch_async(dispatch_get_main_queue(), ^{
+ [self.delegate webUploader:self didCreateDirectoryAtPath:absolutePath];
+ });
+ }
+ return [GCDWebServerDataResponse responseWithJSONObject:@{}];
+}
+
+@end
+
+@implementation GCDWebUploader
+
+@synthesize uploadDirectory=_uploadDirectory, allowedFileExtensions=_allowedExtensions, allowHiddenItems=_allowHidden,
+ title=_title, header=_header, prologue=_prologue, epilogue=_epilogue, footer=_footer;
+
++@dynamic delegate;
++
+- (instancetype)initWithUploadDirectory:(NSString*)path {
+ if ((self = [super init])) {
- NSBundle* siteBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"GCDWebUploader" ofType:@"bundle"]];
++ NSBundle* siteBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[GCDWebUploader class]] pathForResource:@"GCDWebUploader" ofType:@"bundle"]];
+ if (siteBundle == nil) {
+ return nil;
+ }
+ _uploadDirectory = [[path stringByStandardizingPath] copy];
+ GCDWebUploader* __unsafe_unretained server = self;
+
+ // Resource files
+ [self addGETHandlerForBasePath:@"/" directoryPath:[siteBundle resourcePath] indexFilename:nil cacheAge:3600 allowRangeRequests:NO];
+
+ // Web page
+ [self addHandlerForMethod:@"GET" path:@"/" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+
+#if TARGET_OS_IPHONE
+ NSString* device = [[UIDevice currentDevice] name];
+#else
+ NSString* device = CFBridgingRelease(SCDynamicStoreCopyComputerName(NULL, NULL));
+#endif
+ NSString* title = server.title;
+ if (title == nil) {
+ title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
+ if (title == nil) {
+ title = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
+ }
+#if !TARGET_OS_IPHONE
+ if (title == nil) {
+ title = [[NSProcessInfo processInfo] processName];
+ }
+#endif
+ }
+ NSString* header = server.header;
+ if (header == nil) {
+ header = title;
+ }
+ NSString* prologue = server.prologue;
+ if (prologue == nil) {
+ prologue = [siteBundle localizedStringForKey:@"PROLOGUE" value:@"" table:nil];
+ }
+ NSString* epilogue = server.epilogue;
+ if (epilogue == nil) {
+ epilogue = [siteBundle localizedStringForKey:@"EPILOGUE" value:@"" table:nil];
+ }
+ NSString* footer = server.footer;
+ if (footer == nil) {
+ NSString* name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
+ NSString* version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
+#if !TARGET_OS_IPHONE
+ if (!name && !version) {
+ name = @"OS X";
+ version = [[NSProcessInfo processInfo] operatingSystemVersionString];
+ }
+#endif
+ footer = [NSString stringWithFormat:[siteBundle localizedStringForKey:@"FOOTER_FORMAT" value:@"" table:nil], name, version];
+ }
+ return [GCDWebServerDataResponse responseWithHTMLTemplate:[siteBundle pathForResource:@"index" ofType:@"html"]
+ variables:@{
+ @"device": device,
+ @"title": title,
+ @"header": header,
+ @"prologue": prologue,
+ @"epilogue": epilogue,
+ @"footer": footer
+ }];
+
+ }];
+
+ // File listing
+ [self addHandlerForMethod:@"GET" path:@"/list" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server listDirectory:request];
+ }];
+
+ // File download
+ [self addHandlerForMethod:@"GET" path:@"/download" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server downloadFile:request];
+ }];
+
+ // File upload
+ [self addHandlerForMethod:@"POST" path:@"/upload" requestClass:[GCDWebServerMultiPartFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server uploadFile:(GCDWebServerMultiPartFormRequest*)request];
+ }];
+
+ // File and folder moving
+ [self addHandlerForMethod:@"POST" path:@"/move" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server moveItem:(GCDWebServerURLEncodedFormRequest*)request];
+ }];
+
+ // File and folder deletion
+ [self addHandlerForMethod:@"POST" path:@"/delete" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server deleteItem:(GCDWebServerURLEncodedFormRequest*)request];
+ }];
+
+ // Directory creation
+ [self addHandlerForMethod:@"POST" path:@"/create" requestClass:[GCDWebServerURLEncodedFormRequest class] processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
+ return [server createDirectory:(GCDWebServerURLEncodedFormRequest*)request];
+ }];
+
+ }
+ return self;
+}
+
+@end
+
+@implementation GCDWebUploader (Subclassing)
+
+- (BOOL)shouldUploadFileAtPath:(NSString*)path withTemporaryFile:(NSString*)tempPath {
+ return YES;
+}
+
+- (BOOL)shouldMoveItemFromPath:(NSString*)fromPath toPath:(NSString*)toPath {
+ return YES;
+}
+
+- (BOOL)shouldDeleteItemAtPath:(NSString*)path {
+ return YES;
+}
+
+- (BOOL)shouldCreateDirectoryAtPath:(NSString*)path {
+ return YES;
+}
+
+@end
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org