",
81 | title, title, _EscapeHTMLString(message), error];
82 | if ((self = [self initWithHTML:html])) {
83 | self.statusCode = statusCode;
84 | }
85 | return self;
86 | }
87 |
88 | - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
89 | GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
90 | va_list arguments;
91 | va_start(arguments, format);
92 | self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
93 | va_end(arguments);
94 | return self;
95 | }
96 |
97 | - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
98 | GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
99 | va_list arguments;
100 | va_start(arguments, format);
101 | self = [self initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
102 | va_end(arguments);
103 | return self;
104 | }
105 |
106 | - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
107 | GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
108 | va_list arguments;
109 | va_start(arguments, format);
110 | self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
111 | va_end(arguments);
112 | return self;
113 | }
114 |
115 | - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
116 | GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
117 | va_list arguments;
118 | va_start(arguments, format);
119 | self = [self initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
120 | va_end(arguments);
121 | return self;
122 | }
123 |
124 | @end
125 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebServer/Responses/GCDWebServerFileResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2015, Pierre-Olivier Latour
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * The name of Pierre-Olivier Latour may not be used to endorse
13 | or promote products derived from this software without specific
14 | prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #import "GCDWebServerResponse.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerFileResponse subclass of GCDWebServerResponse reads the body
34 | * of the HTTP response from a file on disk.
35 | *
36 | * It will automatically set the contentType, lastModifiedDate and eTag
37 | * properties of the GCDWebServerResponse according to the file extension and
38 | * metadata.
39 | */
40 | @interface GCDWebServerFileResponse : GCDWebServerResponse
41 | @property(nonatomic, copy) NSString* contentType; // Redeclare as non-null
42 | @property(nonatomic) NSDate* lastModifiedDate; // Redeclare as non-null
43 | @property(nonatomic, copy) NSString* eTag; // Redeclare as non-null
44 |
45 | /**
46 | * Creates a response with the contents of a file.
47 | */
48 | + (nullable instancetype)responseWithFile:(NSString*)path;
49 |
50 | /**
51 | * Creates a response like +responseWithFile: and sets the "Content-Disposition"
52 | * HTTP header for a download if the "attachment" argument is YES.
53 | */
54 | + (nullable instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment;
55 |
56 | /**
57 | * Creates a response like +responseWithFile: but restricts the file contents
58 | * to a specific byte range.
59 | *
60 | * See -initWithFile:byteRange: for details.
61 | */
62 | + (nullable instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range;
63 |
64 | /**
65 | * Creates a response like +responseWithFile:byteRange: and sets the
66 | * "Content-Disposition" HTTP header for a download if the "attachment"
67 | * argument is YES.
68 | */
69 | + (nullable instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment;
70 |
71 | /**
72 | * Initializes a response with the contents of a file.
73 | */
74 | - (nullable instancetype)initWithFile:(NSString*)path;
75 |
76 | /**
77 | * Initializes a response like +responseWithFile: and sets the
78 | * "Content-Disposition" HTTP header for a download if the "attachment"
79 | * argument is YES.
80 | */
81 | - (nullable instancetype)initWithFile:(NSString*)path isAttachment:(BOOL)attachment;
82 |
83 | /**
84 | * Initializes a response like -initWithFile: but restricts the file contents
85 | * to a specific byte range. This range should be set to (NSUIntegerMax, 0) for
86 | * the full file, (offset, length) if expressed from the beginning of the file,
87 | * or (NSUIntegerMax, length) if expressed from the end of the file. The "offset"
88 | * and "length" values will be automatically adjusted to be compatible with the
89 | * actual size of the file.
90 | *
91 | * This argument would typically be set to the value of the byteRange property
92 | * of the current GCDWebServerRequest.
93 | */
94 | - (nullable instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range;
95 |
96 | /**
97 | * This method is the designated initializer for the class.
98 | *
99 | * If MIME type overrides are specified, they allow to customize the built-in
100 | * mapping from extensions to MIME types. Keys of the dictionary must be lowercased
101 | * file extensions without the period, and the values must be the corresponding
102 | * MIME types.
103 | */
104 | - (nullable instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment mimeTypeOverrides:(nullable NSDictionary*)overrides;
105 |
106 | @end
107 |
108 | NS_ASSUME_NONNULL_END
109 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebServer/Responses/GCDWebServerFileResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2015, Pierre-Olivier Latour
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * The name of Pierre-Olivier Latour may not be used to endorse
13 | or promote products derived from this software without specific
14 | prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #if !__has_feature(objc_arc)
29 | #error GCDWebServer requires ARC
30 | #endif
31 |
32 | #import
33 |
34 | #import "GCDWebServerPrivate.h"
35 |
36 | #define kFileReadBufferSize (32 * 1024)
37 |
38 | @implementation GCDWebServerFileResponse {
39 | NSString* _path;
40 | NSUInteger _offset;
41 | NSUInteger _size;
42 | int _file;
43 | }
44 |
45 | @dynamic contentType, lastModifiedDate, eTag;
46 |
47 | + (instancetype)responseWithFile:(NSString*)path {
48 | return [[[self class] alloc] initWithFile:path];
49 | }
50 |
51 | + (instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment {
52 | return [[[self class] alloc] initWithFile:path isAttachment:attachment];
53 | }
54 |
55 | + (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range {
56 | return [[[self class] alloc] initWithFile:path byteRange:range];
57 | }
58 |
59 | + (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
60 | return [[[self class] alloc] initWithFile:path byteRange:range isAttachment:attachment mimeTypeOverrides:nil];
61 | }
62 |
63 | - (instancetype)initWithFile:(NSString*)path {
64 | return [self initWithFile:path byteRange:NSMakeRange(NSUIntegerMax, 0) isAttachment:NO mimeTypeOverrides:nil];
65 | }
66 |
67 | - (instancetype)initWithFile:(NSString*)path isAttachment:(BOOL)attachment {
68 | return [self initWithFile:path byteRange:NSMakeRange(NSUIntegerMax, 0) isAttachment:attachment mimeTypeOverrides:nil];
69 | }
70 |
71 | - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range {
72 | return [self initWithFile:path byteRange:range isAttachment:NO mimeTypeOverrides:nil];
73 | }
74 |
75 | static inline NSDate* _NSDateFromTimeSpec(const struct timespec* t) {
76 | return [NSDate dateWithTimeIntervalSince1970:((NSTimeInterval)t->tv_sec + (NSTimeInterval)t->tv_nsec / 1000000000.0)];
77 | }
78 |
79 | - (instancetype)initWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment mimeTypeOverrides:(NSDictionary*)overrides {
80 | struct stat info;
81 | if (lstat([path fileSystemRepresentation], &info) || !(info.st_mode & S_IFREG)) {
82 | GWS_DNOT_REACHED();
83 | return nil;
84 | }
85 | #ifndef __LP64__
86 | 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)
87 | GWS_DNOT_REACHED();
88 | return nil;
89 | }
90 | #endif
91 | NSUInteger fileSize = (NSUInteger)info.st_size;
92 |
93 | BOOL hasByteRange = GCDWebServerIsValidByteRange(range);
94 | if (hasByteRange) {
95 | if (range.location != NSUIntegerMax) {
96 | range.location = MIN(range.location, fileSize);
97 | range.length = MIN(range.length, fileSize - range.location);
98 | } else {
99 | range.length = MIN(range.length, fileSize);
100 | range.location = fileSize - range.length;
101 | }
102 | if (range.length == 0) {
103 | return nil; // TODO: Return 416 status code and "Content-Range: bytes */{file length}" header
104 | }
105 | } else {
106 | range.location = 0;
107 | range.length = fileSize;
108 | }
109 |
110 | if ((self = [super init])) {
111 | _path = [path copy];
112 | _offset = range.location;
113 | _size = range.length;
114 | if (hasByteRange) {
115 | [self setStatusCode:kGCDWebServerHTTPStatusCode_PartialContent];
116 | [self setValue:[NSString stringWithFormat:@"bytes %lu-%lu/%lu", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), (unsigned long)fileSize] forAdditionalHeader:@"Content-Range"];
117 | GWS_LOG_DEBUG(@"Using content bytes range [%lu-%lu] for file \"%@\"", (unsigned long)_offset, (unsigned long)(_offset + _size - 1), path);
118 | }
119 |
120 | if (attachment) {
121 | NSString* fileName = [path lastPathComponent];
122 | NSData* data = [[fileName stringByReplacingOccurrencesOfString:@"\"" withString:@""] dataUsingEncoding:NSISOLatin1StringEncoding allowLossyConversion:YES];
123 | NSString* lossyFileName = data ? [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding] : nil;
124 | if (lossyFileName) {
125 | NSString* value = [NSString stringWithFormat:@"attachment; filename=\"%@\"; filename*=UTF-8''%@", lossyFileName, GCDWebServerEscapeURLString(fileName)];
126 | [self setValue:value forAdditionalHeader:@"Content-Disposition"];
127 | } else {
128 | GWS_DNOT_REACHED();
129 | }
130 | }
131 |
132 | self.contentType = GCDWebServerGetMimeTypeForExtension([_path pathExtension], overrides);
133 | self.contentLength = _size;
134 | self.lastModifiedDate = _NSDateFromTimeSpec(&info.st_mtimespec);
135 | self.eTag = [NSString stringWithFormat:@"%llu/%li/%li", info.st_ino, info.st_mtimespec.tv_sec, info.st_mtimespec.tv_nsec];
136 | }
137 | return self;
138 | }
139 |
140 | - (BOOL)open:(NSError**)error {
141 | _file = open([_path fileSystemRepresentation], O_NOFOLLOW | O_RDONLY);
142 | if (_file <= 0) {
143 | if (error) {
144 | *error = GCDWebServerMakePosixError(errno);
145 | }
146 | return NO;
147 | }
148 | if (lseek(_file, _offset, SEEK_SET) != (off_t)_offset) {
149 | if (error) {
150 | *error = GCDWebServerMakePosixError(errno);
151 | }
152 | close(_file);
153 | return NO;
154 | }
155 | return YES;
156 | }
157 |
158 | - (NSData*)readData:(NSError**)error {
159 | size_t length = MIN((NSUInteger)kFileReadBufferSize, _size);
160 | NSMutableData* data = [[NSMutableData alloc] initWithLength:length];
161 | ssize_t result = read(_file, data.mutableBytes, length);
162 | if (result < 0) {
163 | if (error) {
164 | *error = GCDWebServerMakePosixError(errno);
165 | }
166 | return nil;
167 | }
168 | if (result > 0) {
169 | [data setLength:result];
170 | _size -= result;
171 | }
172 | return data;
173 | }
174 |
175 | - (void)close {
176 | close(_file);
177 | }
178 |
179 | - (NSString*)description {
180 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
181 | [description appendFormat:@"\n\n{%@}", _path];
182 | return description;
183 | }
184 |
185 | @end
186 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebServer/Responses/GCDWebServerStreamedResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2015, Pierre-Olivier Latour
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * The name of Pierre-Olivier Latour may not be used to endorse
13 | or promote products derived from this software without specific
14 | prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #import "GCDWebServerResponse.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerStreamBlock is called to stream the data for the HTTP body.
34 | * The block must return either a chunk of data, an empty NSData when done, or
35 | * nil on error and set the "error" argument which is guaranteed to be non-NULL.
36 | */
37 | typedef NSData* _Nullable (^GCDWebServerStreamBlock)(NSError** error);
38 |
39 | /**
40 | * The GCDWebServerAsyncStreamBlock works like the GCDWebServerStreamBlock
41 | * except the streamed data can be returned at a later time allowing for
42 | * truly asynchronous generation of the data.
43 | *
44 | * The block must call "completionBlock" passing the new chunk of data when ready,
45 | * an empty NSData when done, or nil on error and pass a NSError.
46 | *
47 | * The block cannot call "completionBlock" more than once per invocation.
48 | */
49 | typedef void (^GCDWebServerAsyncStreamBlock)(GCDWebServerBodyReaderCompletionBlock completionBlock);
50 |
51 | /**
52 | * The GCDWebServerStreamedResponse subclass of GCDWebServerResponse streams
53 | * the body of the HTTP response using a GCD block.
54 | */
55 | @interface GCDWebServerStreamedResponse : GCDWebServerResponse
56 | @property(nonatomic, copy) NSString* contentType; // Redeclare as non-null
57 |
58 | /**
59 | * Creates a response with streamed data and a given content type.
60 | */
61 | + (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
62 |
63 | /**
64 | * Creates a response with async streamed data and a given content type.
65 | */
66 | + (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
67 |
68 | /**
69 | * Initializes a response with streamed data and a given content type.
70 | */
71 | - (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block;
72 |
73 | /**
74 | * This method is the designated initializer for the class.
75 | */
76 | - (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block;
77 |
78 | @end
79 |
80 | NS_ASSUME_NONNULL_END
81 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebServer/Responses/GCDWebServerStreamedResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2015, Pierre-Olivier Latour
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * The name of Pierre-Olivier Latour may not be used to endorse
13 | or promote products derived from this software without specific
14 | prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | #if !__has_feature(objc_arc)
29 | #error GCDWebServer requires ARC
30 | #endif
31 |
32 | #import "GCDWebServerPrivate.h"
33 |
34 | @implementation GCDWebServerStreamedResponse {
35 | GCDWebServerAsyncStreamBlock _block;
36 | }
37 |
38 | @dynamic contentType;
39 |
40 | + (instancetype)responseWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
41 | return [[[self class] alloc] initWithContentType:type streamBlock:block];
42 | }
43 |
44 | + (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
45 | return [[[self class] alloc] initWithContentType:type asyncStreamBlock:block];
46 | }
47 |
48 | - (instancetype)initWithContentType:(NSString*)type streamBlock:(GCDWebServerStreamBlock)block {
49 | return [self initWithContentType:type
50 | asyncStreamBlock:^(GCDWebServerBodyReaderCompletionBlock completionBlock) {
51 |
52 | NSError* error = nil;
53 | NSData* data = block(&error);
54 | completionBlock(data, error);
55 |
56 | }];
57 | }
58 |
59 | - (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
60 | if ((self = [super init])) {
61 | _block = [block copy];
62 |
63 | self.contentType = type;
64 | }
65 | return self;
66 | }
67 |
68 | - (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
69 | _block(block);
70 | }
71 |
72 | - (NSString*)description {
73 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
74 | [description appendString:@"\n\n"];
75 | return description;
76 | }
77 |
78 | @end
79 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebUploader/GCDWebUploader.bundle/Contents/Info.plist:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sjxjjx/GCDWebServerDemo/e6cee9613e6ebcf3866093959d2ead7ebbb1cbea/GCDWebServerDemo/GCDWebUploader/GCDWebUploader.bundle/Contents/Info.plist
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2015, Pierre-Olivier Latour
3 | All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * The name of Pierre-Olivier Latour may not be used to endorse
13 | or promote products derived from this software without specific
14 | prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | */
27 |
28 | .row-file {
29 | height: 40px;
30 | }
31 |
32 | .column-icon {
33 | width: 40px;
34 | text-align: center;
35 | }
36 |
37 | .column-name {
38 | }
39 |
40 | .column-size {
41 | width: 100px;
42 | text-align: right;
43 | }
44 |
45 | .column-move {
46 | width: 40px;
47 | text-align: center;
48 | }
49 |
50 | .column-delete {
51 | width: 40px;
52 | text-align: center;
53 | }
54 |
55 | .column-path {
56 | }
57 |
58 | .column-progress {
59 | width: 200px;
60 | }
61 |
62 | .footer {
63 | color: #999;
64 | text-align: center;
65 | font-size: 0.9em;
66 | }
67 |
68 | #reload {
69 | float: right;
70 | }
71 |
72 | #create-input {
73 | width: 50%;
74 | height: 20px;
75 | }
76 |
77 | #move-input {
78 | width: 80%;
79 | height: 20px;
80 | }
81 |
82 | /* Bootstrap overrides */
83 |
84 | .btn:focus {
85 | outline: none; /* FIXME: Work around for Chrome only but still draws focus ring while button pressed */
86 | }
87 |
88 | .btn-toolbar {
89 | margin-top: 30px;
90 | margin-bottom: 20px;
91 | }
92 |
93 | .table .progress {
94 | margin-top: 0px;
95 | margin-bottom: 0px;
96 | height: 16px;
97 | }
98 |
99 | .panel-default > .panel-heading {
100 | color: #555;
101 | }
102 |
103 | .breadcrumb {
104 | background-color: transparent;
105 | border-radius: 0px;
106 | margin-bottom: 0px;
107 | padding: 0px;
108 | }
109 |
110 | .breadcrumb > .active {
111 | color: #555;
112 | }
113 |
114 | .breadcrumb > li + li:before {
115 | color: #999;
116 | }
117 |
118 | .table > tbody > tr > td {
119 | vertical-align: middle;
120 | }
121 |
122 | .table > tbody > tr > td > p {
123 | margin: 0px;
124 | }
125 |
126 | /* Initial state */
127 |
128 | .uploading {
129 | display: none;
130 | }
131 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/css/jquery.fileupload.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | /*
3 | * jQuery File Upload Plugin CSS 1.3.0
4 | * https://github.com/blueimp/jQuery-File-Upload
5 | *
6 | * Copyright 2013, Sebastian Tschan
7 | * https://blueimp.net
8 | *
9 | * Licensed under the MIT license:
10 | * http://www.opensource.org/licenses/MIT
11 | */
12 |
13 | .fileinput-button {
14 | position: relative;
15 | overflow: hidden;
16 | }
17 | .fileinput-button input {
18 | position: absolute;
19 | top: 0;
20 | right: 0;
21 | margin: 0;
22 | opacity: 0;
23 | -ms-filter: 'alpha(opacity=0)';
24 | font-size: 200px;
25 | direction: ltr;
26 | cursor: pointer;
27 | }
28 |
29 | /* Fixes for IE < 8 */
30 | @media screen\9 {
31 | .fileinput-button input {
32 | filter: alpha(opacity=0);
33 | font-size: 100%;
34 | height: 100%;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/GCDWebServerDemo/GCDWebUploader/GCDWebUploader.bundle/Contents/Resources/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
1 | "PROLOGUE" = "
Drag & drop files on this window or use the \"Upload Files…\" button to upload new files.