├── hopper_api.py
├── hopper_helper
├── HopperTweakStudio
│ ├── Info.plist
│ └── launch_shim.m
├── Podfile
├── Podfile.lock
├── Pods
│ ├── GCDWebServer
│ │ ├── GCDWebServer
│ │ │ ├── Core
│ │ │ │ ├── GCDWebServer.h
│ │ │ │ ├── GCDWebServer.m
│ │ │ │ ├── GCDWebServerConnection.h
│ │ │ │ ├── GCDWebServerConnection.m
│ │ │ │ ├── GCDWebServerFunctions.h
│ │ │ │ ├── GCDWebServerFunctions.m
│ │ │ │ ├── GCDWebServerHTTPStatusCodes.h
│ │ │ │ ├── GCDWebServerPrivate.h
│ │ │ │ ├── GCDWebServerRequest.h
│ │ │ │ ├── GCDWebServerRequest.m
│ │ │ │ ├── GCDWebServerResponse.h
│ │ │ │ └── GCDWebServerResponse.m
│ │ │ ├── Requests
│ │ │ │ ├── GCDWebServerDataRequest.h
│ │ │ │ ├── GCDWebServerDataRequest.m
│ │ │ │ ├── GCDWebServerFileRequest.h
│ │ │ │ ├── GCDWebServerFileRequest.m
│ │ │ │ ├── GCDWebServerMultiPartFormRequest.h
│ │ │ │ ├── GCDWebServerMultiPartFormRequest.m
│ │ │ │ ├── GCDWebServerURLEncodedFormRequest.h
│ │ │ │ └── GCDWebServerURLEncodedFormRequest.m
│ │ │ └── Responses
│ │ │ │ ├── GCDWebServerDataResponse.h
│ │ │ │ ├── GCDWebServerDataResponse.m
│ │ │ │ ├── GCDWebServerErrorResponse.h
│ │ │ │ ├── GCDWebServerErrorResponse.m
│ │ │ │ ├── GCDWebServerFileResponse.h
│ │ │ │ ├── GCDWebServerFileResponse.m
│ │ │ │ ├── GCDWebServerStreamedResponse.h
│ │ │ │ └── GCDWebServerStreamedResponse.m
│ │ ├── LICENSE
│ │ └── README.md
│ ├── Headers
│ │ ├── Private
│ │ │ └── GCDWebServer
│ │ │ │ ├── GCDWebServer.h
│ │ │ │ ├── GCDWebServerConnection.h
│ │ │ │ ├── GCDWebServerDataRequest.h
│ │ │ │ ├── GCDWebServerDataResponse.h
│ │ │ │ ├── GCDWebServerErrorResponse.h
│ │ │ │ ├── GCDWebServerFileRequest.h
│ │ │ │ ├── GCDWebServerFileResponse.h
│ │ │ │ ├── GCDWebServerFunctions.h
│ │ │ │ ├── GCDWebServerHTTPStatusCodes.h
│ │ │ │ ├── GCDWebServerMultiPartFormRequest.h
│ │ │ │ ├── GCDWebServerPrivate.h
│ │ │ │ ├── GCDWebServerRequest.h
│ │ │ │ ├── GCDWebServerResponse.h
│ │ │ │ ├── GCDWebServerStreamedResponse.h
│ │ │ │ └── GCDWebServerURLEncodedFormRequest.h
│ │ └── Public
│ │ │ └── GCDWebServer
│ │ │ ├── GCDWebServer.h
│ │ │ ├── GCDWebServerConnection.h
│ │ │ ├── GCDWebServerDataRequest.h
│ │ │ ├── GCDWebServerDataResponse.h
│ │ │ ├── GCDWebServerErrorResponse.h
│ │ │ ├── GCDWebServerFileRequest.h
│ │ │ ├── GCDWebServerFileResponse.h
│ │ │ ├── GCDWebServerFunctions.h
│ │ │ ├── GCDWebServerHTTPStatusCodes.h
│ │ │ ├── GCDWebServerMultiPartFormRequest.h
│ │ │ ├── GCDWebServerRequest.h
│ │ │ ├── GCDWebServerResponse.h
│ │ │ ├── GCDWebServerStreamedResponse.h
│ │ │ └── GCDWebServerURLEncodedFormRequest.h
│ ├── Manifest.lock
│ ├── Pods.xcodeproj
│ │ ├── project.pbxproj
│ │ └── xcuserdata
│ │ │ └── ethanarbuckle.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── GCDWebServer.xcscheme
│ │ │ ├── Pods-hopper_helper.xcscheme
│ │ │ └── xcschememanagement.plist
│ └── Target Support Files
│ │ ├── GCDWebServer
│ │ ├── GCDWebServer-dummy.m
│ │ ├── GCDWebServer-prefix.pch
│ │ ├── GCDWebServer.debug.xcconfig
│ │ └── GCDWebServer.release.xcconfig
│ │ └── Pods-hopper_helper
│ │ ├── Pods-hopper_helper-acknowledgements.markdown
│ │ ├── Pods-hopper_helper-acknowledgements.plist
│ │ ├── Pods-hopper_helper-dummy.m
│ │ ├── Pods-hopper_helper.debug.xcconfig
│ │ └── Pods-hopper_helper.release.xcconfig
├── README.md
├── hopper_helper.xcodeproj
│ └── project.pbxproj
├── hopper_helper.xcworkspace
│ └── contents.xcworkspacedata
└── plugin
│ ├── handlers.h
│ ├── handlers.m
│ └── hopper_backend.m
├── hopper_proxy.py
├── lzssdec
├── patch_tcc_db.py
└── run_hopper.py
/hopper_helper/HopperTweakStudio/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | HopperTweakStudio_shim
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | CFPlugInDynamicRegistration
22 | NO
23 | CFPlugInFactories
24 |
25 | 00000000-0000-0000-0000-000000000000
26 | MyFactoryFunction
27 |
28 | CFPlugInTypes
29 |
30 | 00000000-0000-0000-0000-000000000000
31 |
32 | 00000000-0000-0000-0000-000000000000
33 |
34 |
35 | CFPlugInUnloadFunction
36 |
37 | NSHumanReadableCopyright
38 | Copyright © Ethan Arbuckle. All rights reserved.
39 | NSPrincipalClass
40 | MIPSCPU
41 |
42 |
43 |
--------------------------------------------------------------------------------
/hopper_helper/HopperTweakStudio/launch_shim.m:
--------------------------------------------------------------------------------
1 | //
2 | // launch_shim.m
3 | // launch_shim
4 | //
5 | // Created by Ethan Arbuckle on 4/10/21.
6 | //
7 |
8 | #include
9 | #include
10 |
11 | // Hopper will refuse to load plugins that have unexpected load commands or utilize common posix symbols.
12 | // To work around this, this minimal binary is loaded by Hopper, and from here the real plugin is opened.
13 |
14 | __attribute__((constructor)) void init(void) {
15 |
16 | NSLog(@"TweakStudio loader injected");
17 |
18 | // Hopper does not allow plugins to use dlopen(), but it does not restrict dlsym().
19 | // Use dlsym to get the dlopen pointer, then load the real plugin dylib
20 | void *(*sym_dlopen)(const char *, int) = dlsym(RTLD_DEFAULT, "dlopen");
21 | const char *dylib = [[@"~/Library/Application Support/Hopper/PlugIns/v4/CPUs/HopperTweakStudio.hopperCPU/HopperTweakStudio" stringByExpandingTildeInPath] UTF8String];
22 | sym_dlopen(dylib, RTLD_NOW);
23 | }
24 |
--------------------------------------------------------------------------------
/hopper_helper/Podfile:
--------------------------------------------------------------------------------
1 | target 'pluginBackend' do
2 | pod "GCDWebServer", "~> 3.0"
3 | end
4 |
--------------------------------------------------------------------------------
/hopper_helper/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - GCDWebServer (3.5.4):
3 | - GCDWebServer/Core (= 3.5.4)
4 | - GCDWebServer/Core (3.5.4)
5 |
6 | DEPENDENCIES:
7 | - GCDWebServer (~> 3.0)
8 |
9 | SPEC REPOS:
10 | trunk:
11 | - GCDWebServer
12 |
13 | SPEC CHECKSUMS:
14 | GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
15 |
16 | PODFILE CHECKSUM: 278b91d4fba272f8f3d2e61a0855a98125a6b524
17 |
18 | COCOAPODS: 1.10.1
19 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServer.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | @class GCDWebServerHandler;
33 |
34 | /**
35 | * The GCDWebServerConnection class is instantiated by GCDWebServer to handle
36 | * each new HTTP connection. Each instance stays alive until the connection is
37 | * closed.
38 | *
39 | * You cannot use this class directly, but it is made public so you can
40 | * subclass it to override some hooks. Use the GCDWebServerOption_ConnectionClass
41 | * option for GCDWebServer to install your custom subclass.
42 | *
43 | * @warning The GCDWebServerConnection retains the GCDWebServer until the
44 | * connection is closed.
45 | */
46 | @interface GCDWebServerConnection : NSObject
47 |
48 | /**
49 | * Returns the GCDWebServer that owns the connection.
50 | */
51 | @property(nonatomic, readonly) GCDWebServer* server;
52 |
53 | /**
54 | * Returns YES if the connection is using IPv6.
55 | */
56 | @property(nonatomic, readonly, getter=isUsingIPv6) BOOL usingIPv6;
57 |
58 | /**
59 | * Returns the address of the local peer (i.e. server) of the connection
60 | * as a raw "struct sockaddr".
61 | */
62 | @property(nonatomic, readonly) NSData* localAddressData;
63 |
64 | /**
65 | * Returns the address of the local peer (i.e. server) of the connection
66 | * as a string.
67 | */
68 | @property(nonatomic, readonly) NSString* localAddressString;
69 |
70 | /**
71 | * Returns the address of the remote peer (i.e. client) of the connection
72 | * as a raw "struct sockaddr".
73 | */
74 | @property(nonatomic, readonly) NSData* remoteAddressData;
75 |
76 | /**
77 | * Returns the address of the remote peer (i.e. client) of the connection
78 | * as a string.
79 | */
80 | @property(nonatomic, readonly) NSString* remoteAddressString;
81 |
82 | /**
83 | * Returns the total number of bytes received from the remote peer (i.e. client)
84 | * so far.
85 | */
86 | @property(nonatomic, readonly) NSUInteger totalBytesRead;
87 |
88 | /**
89 | * Returns the total number of bytes sent to the remote peer (i.e. client) so far.
90 | */
91 | @property(nonatomic, readonly) NSUInteger totalBytesWritten;
92 |
93 | @end
94 |
95 | /**
96 | * Hooks to customize the behavior of GCDWebServer HTTP connections.
97 | *
98 | * @warning These methods can be called on any GCD thread.
99 | * Be sure to also call "super" when overriding them.
100 | */
101 | @interface GCDWebServerConnection (Subclassing)
102 |
103 | /**
104 | * This method is called when the connection is opened.
105 | *
106 | * Return NO to reject the connection e.g. after validating the local
107 | * or remote address.
108 | */
109 | - (BOOL)open;
110 |
111 | /**
112 | * This method is called whenever data has been received
113 | * from the remote peer (i.e. client).
114 | *
115 | * @warning Do not attempt to modify this data.
116 | */
117 | - (void)didReadBytes:(const void*)bytes length:(NSUInteger)length;
118 |
119 | /**
120 | * This method is called whenever data has been sent
121 | * to the remote peer (i.e. client).
122 | *
123 | * @warning Do not attempt to modify this data.
124 | */
125 | - (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length;
126 |
127 | /**
128 | * This method is called after the HTTP headers have been received to
129 | * allow replacing the request URL by another one.
130 | *
131 | * The default implementation returns the original URL.
132 | */
133 | - (NSURL*)rewriteRequestURL:(NSURL*)url withMethod:(NSString*)method headers:(NSDictionary*)headers;
134 |
135 | /**
136 | * Assuming a valid HTTP request was received, this method is called before
137 | * the request is processed.
138 | *
139 | * Return a non-nil GCDWebServerResponse to bypass the request processing entirely.
140 | *
141 | * The default implementation checks for HTTP authentication if applicable
142 | * and returns a barebone 401 status code response if authentication failed.
143 | */
144 | - (nullable GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request;
145 |
146 | /**
147 | * Assuming a valid HTTP request was received and -preflightRequest: returned nil,
148 | * this method is called to process the request by executing the handler's
149 | * process block.
150 | */
151 | - (void)processRequest:(GCDWebServerRequest*)request completion:(GCDWebServerCompletionBlock)completion;
152 |
153 | /**
154 | * Assuming a valid HTTP request was received and either -preflightRequest:
155 | * or -processRequest:completion: returned a non-nil GCDWebServerResponse,
156 | * this method is called to override the response.
157 | *
158 | * You can either modify the current response and return it, or return a
159 | * completely new one.
160 | *
161 | * The default implementation replaces any response matching the "ETag" or
162 | * "Last-Modified-Date" header of the request by a barebone "Not-Modified" (304)
163 | * one.
164 | */
165 | - (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request;
166 |
167 | /**
168 | * This method is called if any error happens while validing or processing
169 | * the request or if no GCDWebServerResponse was generated during processing.
170 | *
171 | * @warning If the request was invalid (e.g. the HTTP headers were malformed),
172 | * the "request" argument will be nil.
173 | */
174 | - (void)abortRequest:(nullable GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode;
175 |
176 | /**
177 | * Called when the connection is closed.
178 | */
179 | - (void)close;
180 |
181 | @end
182 |
183 | NS_ASSUME_NONNULL_END
184 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | #ifdef __cplusplus
33 | extern "C" {
34 | #endif
35 |
36 | /**
37 | * Converts a file extension to the corresponding MIME type.
38 | * If there is no match, "application/octet-stream" is returned.
39 | *
40 | * Overrides allow to customize the built-in mapping from extensions to MIME
41 | * types. Keys of the dictionary must be lowercased file extensions without
42 | * the period, and the values must be the corresponding MIME types.
43 | */
44 | NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension, NSDictionary* _Nullable overrides);
45 |
46 | /**
47 | * Add percent-escapes to a string so it can be used in a URL.
48 | * The legal characters ":@/?&=+" are also escaped to ensure compatibility
49 | * with URL encoded forms and URL queries.
50 | */
51 | NSString* _Nullable GCDWebServerEscapeURLString(NSString* string);
52 |
53 | /**
54 | * Unescapes a URL percent-encoded string.
55 | */
56 | NSString* _Nullable GCDWebServerUnescapeURLString(NSString* string);
57 |
58 | /**
59 | * Extracts the unescaped names and values from an
60 | * "application/x-www-form-urlencoded" form.
61 | * http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
62 | */
63 | NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
64 |
65 | /**
66 | * On OS X, returns the IPv4 or IPv6 address as a string of the primary
67 | * connected service or nil if not available.
68 | *
69 | * On iOS, returns the IPv4 or IPv6 address as a string of the WiFi
70 | * interface if connected or nil otherwise.
71 | */
72 | NSString* _Nullable GCDWebServerGetPrimaryIPAddress(BOOL useIPv6);
73 |
74 | /**
75 | * Converts a date into a string using RFC822 formatting.
76 | * https://tools.ietf.org/html/rfc822#section-5
77 | * https://tools.ietf.org/html/rfc1123#section-5.2.14
78 | */
79 | NSString* GCDWebServerFormatRFC822(NSDate* date);
80 |
81 | /**
82 | * Converts a RFC822 formatted string into a date.
83 | * https://tools.ietf.org/html/rfc822#section-5
84 | * https://tools.ietf.org/html/rfc1123#section-5.2.14
85 | *
86 | * @warning Timezones other than GMT are not supported by this function.
87 | */
88 | NSDate* _Nullable GCDWebServerParseRFC822(NSString* string);
89 |
90 | /**
91 | * Converts a date into a string using IOS 8601 formatting.
92 | * http://tools.ietf.org/html/rfc3339#section-5.6
93 | */
94 | NSString* GCDWebServerFormatISO8601(NSDate* date);
95 |
96 | /**
97 | * Converts a ISO 8601 formatted string into a date.
98 | * http://tools.ietf.org/html/rfc3339#section-5.6
99 | *
100 | * @warning Only "calendar" variant is supported at this time and timezones
101 | * other than GMT are not supported either.
102 | */
103 | NSDate* _Nullable GCDWebServerParseISO8601(NSString* string);
104 |
105 | /**
106 | * Removes "//", "/./" and "/../" components from path as well as any trailing slash.
107 | */
108 | NSString* GCDWebServerNormalizePath(NSString* path);
109 |
110 | #ifdef __cplusplus
111 | }
112 | #endif
113 |
114 | NS_ASSUME_NONNULL_END
115 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 | #if TARGET_OS_IPHONE
34 | #import
35 | #else
36 | #import
37 | #endif
38 | #import
39 |
40 | #import
41 | #import
42 | #import
43 |
44 | #import "GCDWebServerPrivate.h"
45 |
46 | static NSDateFormatter* _dateFormatterRFC822 = nil;
47 | static NSDateFormatter* _dateFormatterISO8601 = nil;
48 | static dispatch_queue_t _dateFormatterQueue = NULL;
49 |
50 | // TODO: Handle RFC 850 and ANSI C's asctime() format
51 | void GCDWebServerInitializeFunctions() {
52 | GWS_DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread
53 | if (_dateFormatterRFC822 == nil) {
54 | _dateFormatterRFC822 = [[NSDateFormatter alloc] init];
55 | _dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
56 | _dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
57 | _dateFormatterRFC822.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
58 | GWS_DCHECK(_dateFormatterRFC822);
59 | }
60 | if (_dateFormatterISO8601 == nil) {
61 | _dateFormatterISO8601 = [[NSDateFormatter alloc] init];
62 | _dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
63 | _dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
64 | _dateFormatterISO8601.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
65 | GWS_DCHECK(_dateFormatterISO8601);
66 | }
67 | if (_dateFormatterQueue == NULL) {
68 | _dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
69 | GWS_DCHECK(_dateFormatterQueue);
70 | }
71 | }
72 |
73 | NSString* GCDWebServerNormalizeHeaderValue(NSString* value) {
74 | if (value) {
75 | NSRange range = [value rangeOfString:@";"]; // Assume part before ";" separator is case-insensitive
76 | if (range.location != NSNotFound) {
77 | value = [[[value substringToIndex:range.location] lowercaseString] stringByAppendingString:[value substringFromIndex:range.location]];
78 | } else {
79 | value = [value lowercaseString];
80 | }
81 | }
82 | return value;
83 | }
84 |
85 | NSString* GCDWebServerTruncateHeaderValue(NSString* value) {
86 | if (value) {
87 | NSRange range = [value rangeOfString:@";"];
88 | if (range.location != NSNotFound) {
89 | return [value substringToIndex:range.location];
90 | }
91 | }
92 | return value;
93 | }
94 |
95 | NSString* GCDWebServerExtractHeaderValueParameter(NSString* value, NSString* name) {
96 | NSString* parameter = nil;
97 | if (value) {
98 | NSScanner* scanner = [[NSScanner alloc] initWithString:value];
99 | [scanner setCaseSensitive:NO]; // Assume parameter names are case-insensitive
100 | NSString* string = [NSString stringWithFormat:@"%@=", name];
101 | if ([scanner scanUpToString:string intoString:NULL]) {
102 | [scanner scanString:string intoString:NULL];
103 | if ([scanner scanString:@"\"" intoString:NULL]) {
104 | [scanner scanUpToString:@"\"" intoString:¶meter];
105 | } else {
106 | [scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:¶meter];
107 | }
108 | }
109 | }
110 | return parameter;
111 | }
112 |
113 | // http://www.w3schools.com/tags/ref_charactersets.asp
114 | NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
115 | NSStringEncoding encoding = kCFStringEncodingInvalidId;
116 | if (charset) {
117 | encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset));
118 | }
119 | return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
120 | }
121 |
122 | NSString* GCDWebServerFormatRFC822(NSDate* date) {
123 | __block NSString* string;
124 | dispatch_sync(_dateFormatterQueue, ^{
125 | string = [_dateFormatterRFC822 stringFromDate:date];
126 | });
127 | return string;
128 | }
129 |
130 | NSDate* GCDWebServerParseRFC822(NSString* string) {
131 | __block NSDate* date;
132 | dispatch_sync(_dateFormatterQueue, ^{
133 | date = [_dateFormatterRFC822 dateFromString:string];
134 | });
135 | return date;
136 | }
137 |
138 | NSString* GCDWebServerFormatISO8601(NSDate* date) {
139 | __block NSString* string;
140 | dispatch_sync(_dateFormatterQueue, ^{
141 | string = [_dateFormatterISO8601 stringFromDate:date];
142 | });
143 | return string;
144 | }
145 |
146 | NSDate* GCDWebServerParseISO8601(NSString* string) {
147 | __block NSDate* date;
148 | dispatch_sync(_dateFormatterQueue, ^{
149 | date = [_dateFormatterISO8601 dateFromString:string];
150 | });
151 | return date;
152 | }
153 |
154 | BOOL GCDWebServerIsTextContentType(NSString* type) {
155 | return ([type hasPrefix:@"text/"] || [type hasPrefix:@"application/json"] || [type hasPrefix:@"application/xml"]);
156 | }
157 |
158 | NSString* GCDWebServerDescribeData(NSData* data, NSString* type) {
159 | if (GCDWebServerIsTextContentType(type)) {
160 | NSString* charset = GCDWebServerExtractHeaderValueParameter(type, @"charset");
161 | NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
162 | if (string) {
163 | return string;
164 | }
165 | }
166 | return [NSString stringWithFormat:@"<%lu bytes>", (unsigned long)data.length];
167 | }
168 |
169 | NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension, NSDictionary* overrides) {
170 | NSDictionary* builtInOverrides = @{@"css" : @"text/css"};
171 | NSString* mimeType = nil;
172 | extension = [extension lowercaseString];
173 | if (extension.length) {
174 | mimeType = [overrides objectForKey:extension];
175 | if (mimeType == nil) {
176 | mimeType = [builtInOverrides objectForKey:extension];
177 | }
178 | if (mimeType == nil) {
179 | CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
180 | if (uti) {
181 | mimeType = CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
182 | CFRelease(uti);
183 | }
184 | }
185 | }
186 | return mimeType ? mimeType : kGCDWebServerDefaultMimeType;
187 | }
188 |
189 | NSString* GCDWebServerEscapeURLString(NSString* string) {
190 | #pragma clang diagnostic push
191 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
192 | return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
193 | #pragma clang diagnostic pop
194 | }
195 |
196 | NSString* GCDWebServerUnescapeURLString(NSString* string) {
197 | #pragma clang diagnostic push
198 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
199 | return CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
200 | #pragma clang diagnostic pop
201 | }
202 |
203 | NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
204 | NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
205 | NSScanner* scanner = [[NSScanner alloc] initWithString:form];
206 | [scanner setCharactersToBeSkipped:nil];
207 | while (1) {
208 | NSString* key = nil;
209 | if (![scanner scanUpToString:@"=" intoString:&key] || [scanner isAtEnd]) {
210 | break;
211 | }
212 | [scanner setScanLocation:([scanner scanLocation] + 1)];
213 |
214 | NSString* value = nil;
215 | [scanner scanUpToString:@"&" intoString:&value];
216 | if (value == nil) {
217 | value = @"";
218 | }
219 |
220 | key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "];
221 | NSString* unescapedKey = key ? GCDWebServerUnescapeURLString(key) : nil;
222 | value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
223 | NSString* unescapedValue = value ? GCDWebServerUnescapeURLString(value) : nil;
224 | if (unescapedKey && unescapedValue) {
225 | [parameters setObject:unescapedValue forKey:unescapedKey];
226 | } else {
227 | GWS_LOG_WARNING(@"Failed parsing URL encoded form for key \"%@\" and value \"%@\"", key, value);
228 | GWS_DNOT_REACHED();
229 | }
230 |
231 | if ([scanner isAtEnd]) {
232 | break;
233 | }
234 | [scanner setScanLocation:([scanner scanLocation] + 1)];
235 | }
236 | return parameters;
237 | }
238 |
239 | NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL includeService) {
240 | char hostBuffer[NI_MAXHOST];
241 | char serviceBuffer[NI_MAXSERV];
242 | if (getnameinfo(addr, addr->sa_len, hostBuffer, sizeof(hostBuffer), serviceBuffer, sizeof(serviceBuffer), NI_NUMERICHOST | NI_NUMERICSERV | NI_NOFQDN) != 0) {
243 | #if DEBUG
244 | GWS_DNOT_REACHED();
245 | #else
246 | return @"";
247 | #endif
248 | }
249 | return includeService ? [NSString stringWithFormat:@"%s:%s", hostBuffer, serviceBuffer] : (NSString*)[NSString stringWithUTF8String:hostBuffer];
250 | }
251 |
252 | NSString* GCDWebServerGetPrimaryIPAddress(BOOL useIPv6) {
253 | NSString* address = nil;
254 | #if TARGET_OS_IPHONE
255 | #if !TARGET_IPHONE_SIMULATOR && !TARGET_OS_TV
256 | const char* primaryInterface = "en0"; // WiFi interface on iOS
257 | #endif
258 | #else
259 | const char* primaryInterface = NULL;
260 | SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("GCDWebServer"), NULL, NULL);
261 | if (store) {
262 | CFPropertyListRef info = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4")); // There is no equivalent for IPv6 but the primary interface should be the same
263 | if (info) {
264 | NSString* interface = [(__bridge NSDictionary*)info objectForKey:@"PrimaryInterface"];
265 | if (interface) {
266 | primaryInterface = [[NSString stringWithString:interface] UTF8String]; // Copy string to auto-release pool
267 | }
268 | CFRelease(info);
269 | }
270 | CFRelease(store);
271 | }
272 | if (primaryInterface == NULL) {
273 | primaryInterface = "lo0";
274 | }
275 | #endif
276 | struct ifaddrs* list;
277 | if (getifaddrs(&list) >= 0) {
278 | for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) {
279 | #if TARGET_IPHONE_SIMULATOR || TARGET_OS_TV
280 | // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
281 | // Assumption holds for Apple TV running tvOS
282 | if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1"))
283 | #else
284 | if (strcmp(ifap->ifa_name, primaryInterface))
285 | #endif
286 | {
287 | continue;
288 | }
289 | if ((ifap->ifa_flags & IFF_UP) && ((!useIPv6 && (ifap->ifa_addr->sa_family == AF_INET)) || (useIPv6 && (ifap->ifa_addr->sa_family == AF_INET6)))) {
290 | address = GCDWebServerStringFromSockAddr(ifap->ifa_addr, NO);
291 | break;
292 | }
293 | }
294 | freeifaddrs(list);
295 | }
296 | return address;
297 | }
298 |
299 | NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) {
300 | va_list arguments;
301 | va_start(arguments, format);
302 | const char* string = [[[NSString alloc] initWithFormat:format arguments:arguments] UTF8String];
303 | va_end(arguments);
304 | unsigned char md5[CC_MD5_DIGEST_LENGTH];
305 | #pragma clang diagnostic push
306 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
307 | CC_MD5(string, (CC_LONG)strlen(string), md5);
308 | #pragma clang diagnostic pop
309 | char buffer[2 * CC_MD5_DIGEST_LENGTH + 1];
310 | for (int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
311 | unsigned char byte = md5[i];
312 | unsigned char byteHi = (byte & 0xF0) >> 4;
313 | buffer[2 * i + 0] = byteHi >= 10 ? 'a' + byteHi - 10 : '0' + byteHi;
314 | unsigned char byteLo = byte & 0x0F;
315 | buffer[2 * i + 1] = byteLo >= 10 ? 'a' + byteLo - 10 : '0' + byteLo;
316 | }
317 | buffer[2 * CC_MD5_DIGEST_LENGTH] = 0;
318 | return (NSString*)[NSString stringWithUTF8String:buffer];
319 | }
320 |
321 | NSString* GCDWebServerNormalizePath(NSString* path) {
322 | NSMutableArray* components = [[NSMutableArray alloc] init];
323 | for (NSString* component in [path componentsSeparatedByString:@"/"]) {
324 | if ([component isEqualToString:@".."]) {
325 | [components removeLastObject];
326 | } else if (component.length && ![component isEqualToString:@"."]) {
327 | [components addObject:component];
328 | }
329 | }
330 | if (path.length && ([path characterAtIndex:0] == '/')) {
331 | return [@"/" stringByAppendingString:[components componentsJoinedByString:@"/"]]; // Preserve initial slash
332 | }
333 | return [components componentsJoinedByString:@"/"];
334 | }
335 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 | // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
29 | // http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
30 |
31 | #import
32 |
33 | /**
34 | * Convenience constants for "informational" HTTP status codes.
35 | */
36 | typedef NS_ENUM(NSInteger, GCDWebServerInformationalHTTPStatusCode) {
37 | kGCDWebServerHTTPStatusCode_Continue = 100,
38 | kGCDWebServerHTTPStatusCode_SwitchingProtocols = 101,
39 | kGCDWebServerHTTPStatusCode_Processing = 102
40 | };
41 |
42 | /**
43 | * Convenience constants for "successful" HTTP status codes.
44 | */
45 | typedef NS_ENUM(NSInteger, GCDWebServerSuccessfulHTTPStatusCode) {
46 | kGCDWebServerHTTPStatusCode_OK = 200,
47 | kGCDWebServerHTTPStatusCode_Created = 201,
48 | kGCDWebServerHTTPStatusCode_Accepted = 202,
49 | kGCDWebServerHTTPStatusCode_NonAuthoritativeInformation = 203,
50 | kGCDWebServerHTTPStatusCode_NoContent = 204,
51 | kGCDWebServerHTTPStatusCode_ResetContent = 205,
52 | kGCDWebServerHTTPStatusCode_PartialContent = 206,
53 | kGCDWebServerHTTPStatusCode_MultiStatus = 207,
54 | kGCDWebServerHTTPStatusCode_AlreadyReported = 208
55 | };
56 |
57 | /**
58 | * Convenience constants for "redirection" HTTP status codes.
59 | */
60 | typedef NS_ENUM(NSInteger, GCDWebServerRedirectionHTTPStatusCode) {
61 | kGCDWebServerHTTPStatusCode_MultipleChoices = 300,
62 | kGCDWebServerHTTPStatusCode_MovedPermanently = 301,
63 | kGCDWebServerHTTPStatusCode_Found = 302,
64 | kGCDWebServerHTTPStatusCode_SeeOther = 303,
65 | kGCDWebServerHTTPStatusCode_NotModified = 304,
66 | kGCDWebServerHTTPStatusCode_UseProxy = 305,
67 | kGCDWebServerHTTPStatusCode_TemporaryRedirect = 307,
68 | kGCDWebServerHTTPStatusCode_PermanentRedirect = 308
69 | };
70 |
71 | /**
72 | * Convenience constants for "client error" HTTP status codes.
73 | */
74 | typedef NS_ENUM(NSInteger, GCDWebServerClientErrorHTTPStatusCode) {
75 | kGCDWebServerHTTPStatusCode_BadRequest = 400,
76 | kGCDWebServerHTTPStatusCode_Unauthorized = 401,
77 | kGCDWebServerHTTPStatusCode_PaymentRequired = 402,
78 | kGCDWebServerHTTPStatusCode_Forbidden = 403,
79 | kGCDWebServerHTTPStatusCode_NotFound = 404,
80 | kGCDWebServerHTTPStatusCode_MethodNotAllowed = 405,
81 | kGCDWebServerHTTPStatusCode_NotAcceptable = 406,
82 | kGCDWebServerHTTPStatusCode_ProxyAuthenticationRequired = 407,
83 | kGCDWebServerHTTPStatusCode_RequestTimeout = 408,
84 | kGCDWebServerHTTPStatusCode_Conflict = 409,
85 | kGCDWebServerHTTPStatusCode_Gone = 410,
86 | kGCDWebServerHTTPStatusCode_LengthRequired = 411,
87 | kGCDWebServerHTTPStatusCode_PreconditionFailed = 412,
88 | kGCDWebServerHTTPStatusCode_RequestEntityTooLarge = 413,
89 | kGCDWebServerHTTPStatusCode_RequestURITooLong = 414,
90 | kGCDWebServerHTTPStatusCode_UnsupportedMediaType = 415,
91 | kGCDWebServerHTTPStatusCode_RequestedRangeNotSatisfiable = 416,
92 | kGCDWebServerHTTPStatusCode_ExpectationFailed = 417,
93 | kGCDWebServerHTTPStatusCode_UnprocessableEntity = 422,
94 | kGCDWebServerHTTPStatusCode_Locked = 423,
95 | kGCDWebServerHTTPStatusCode_FailedDependency = 424,
96 | kGCDWebServerHTTPStatusCode_UpgradeRequired = 426,
97 | kGCDWebServerHTTPStatusCode_PreconditionRequired = 428,
98 | kGCDWebServerHTTPStatusCode_TooManyRequests = 429,
99 | kGCDWebServerHTTPStatusCode_RequestHeaderFieldsTooLarge = 431
100 | };
101 |
102 | /**
103 | * Convenience constants for "server error" HTTP status codes.
104 | */
105 | typedef NS_ENUM(NSInteger, GCDWebServerServerErrorHTTPStatusCode) {
106 | kGCDWebServerHTTPStatusCode_InternalServerError = 500,
107 | kGCDWebServerHTTPStatusCode_NotImplemented = 501,
108 | kGCDWebServerHTTPStatusCode_BadGateway = 502,
109 | kGCDWebServerHTTPStatusCode_ServiceUnavailable = 503,
110 | kGCDWebServerHTTPStatusCode_GatewayTimeout = 504,
111 | kGCDWebServerHTTPStatusCode_HTTPVersionNotSupported = 505,
112 | kGCDWebServerHTTPStatusCode_InsufficientStorage = 507,
113 | kGCDWebServerHTTPStatusCode_LoopDetected = 508,
114 | kGCDWebServerHTTPStatusCode_NotExtended = 510,
115 | kGCDWebServerHTTPStatusCode_NetworkAuthenticationRequired = 511
116 | };
117 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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
29 | #import
30 |
31 | /**
32 | * All GCDWebServer headers.
33 | */
34 |
35 | #import "GCDWebServerHTTPStatusCodes.h"
36 | #import "GCDWebServerFunctions.h"
37 |
38 | #import "GCDWebServer.h"
39 | #import "GCDWebServerConnection.h"
40 |
41 | #import "GCDWebServerDataRequest.h"
42 | #import "GCDWebServerFileRequest.h"
43 | #import "GCDWebServerMultiPartFormRequest.h"
44 | #import "GCDWebServerURLEncodedFormRequest.h"
45 |
46 | #import "GCDWebServerDataResponse.h"
47 | #import "GCDWebServerErrorResponse.h"
48 | #import "GCDWebServerFileResponse.h"
49 | #import "GCDWebServerStreamedResponse.h"
50 |
51 | /**
52 | * Check if a custom logging facility should be used instead.
53 | */
54 |
55 | #if defined(__GCDWEBSERVER_LOGGING_HEADER__)
56 |
57 | #define __GCDWEBSERVER_LOGGING_FACILITY_CUSTOM__
58 |
59 | #import __GCDWEBSERVER_LOGGING_HEADER__
60 |
61 | /**
62 | * Automatically detect if XLFacility is available and if so use it as a
63 | * logging facility.
64 | */
65 |
66 | #elif defined(__has_include) && __has_include("XLFacilityMacros.h")
67 |
68 | #define __GCDWEBSERVER_LOGGING_FACILITY_XLFACILITY__
69 |
70 | #undef XLOG_TAG
71 | #define XLOG_TAG @"gcdwebserver.internal"
72 |
73 | #import "XLFacilityMacros.h"
74 |
75 | #define GWS_LOG_DEBUG(...) XLOG_DEBUG(__VA_ARGS__)
76 | #define GWS_LOG_VERBOSE(...) XLOG_VERBOSE(__VA_ARGS__)
77 | #define GWS_LOG_INFO(...) XLOG_INFO(__VA_ARGS__)
78 | #define GWS_LOG_WARNING(...) XLOG_WARNING(__VA_ARGS__)
79 | #define GWS_LOG_ERROR(...) XLOG_ERROR(__VA_ARGS__)
80 |
81 | #define GWS_DCHECK(__CONDITION__) XLOG_DEBUG_CHECK(__CONDITION__)
82 | #define GWS_DNOT_REACHED() XLOG_DEBUG_UNREACHABLE()
83 |
84 | /**
85 | * If all of the above fail, then use GCDWebServer built-in
86 | * logging facility.
87 | */
88 |
89 | #else
90 |
91 | #define __GCDWEBSERVER_LOGGING_FACILITY_BUILTIN__
92 |
93 | typedef NS_ENUM(int, GCDWebServerLoggingLevel) {
94 | kGCDWebServerLoggingLevel_Debug = 0,
95 | kGCDWebServerLoggingLevel_Verbose,
96 | kGCDWebServerLoggingLevel_Info,
97 | kGCDWebServerLoggingLevel_Warning,
98 | kGCDWebServerLoggingLevel_Error
99 | };
100 |
101 | extern GCDWebServerLoggingLevel GCDWebServerLogLevel;
102 | extern void GCDWebServerLogMessage(GCDWebServerLoggingLevel level, NSString* _Nonnull format, ...) NS_FORMAT_FUNCTION(2, 3);
103 |
104 | #if DEBUG
105 | #define GWS_LOG_DEBUG(...) \
106 | do { \
107 | if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Debug) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Debug, __VA_ARGS__); \
108 | } while (0)
109 | #else
110 | #define GWS_LOG_DEBUG(...)
111 | #endif
112 | #define GWS_LOG_VERBOSE(...) \
113 | do { \
114 | if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Verbose) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Verbose, __VA_ARGS__); \
115 | } while (0)
116 | #define GWS_LOG_INFO(...) \
117 | do { \
118 | if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Info) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Info, __VA_ARGS__); \
119 | } while (0)
120 | #define GWS_LOG_WARNING(...) \
121 | do { \
122 | if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Warning) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Warning, __VA_ARGS__); \
123 | } while (0)
124 | #define GWS_LOG_ERROR(...) \
125 | do { \
126 | if (GCDWebServerLogLevel <= kGCDWebServerLoggingLevel_Error) GCDWebServerLogMessage(kGCDWebServerLoggingLevel_Error, __VA_ARGS__); \
127 | } while (0)
128 |
129 | #endif
130 |
131 | /**
132 | * Consistency check macros used when building Debug only.
133 | */
134 |
135 | #if !defined(GWS_DCHECK) || !defined(GWS_DNOT_REACHED)
136 |
137 | #if DEBUG
138 |
139 | #define GWS_DCHECK(__CONDITION__) \
140 | do { \
141 | if (!(__CONDITION__)) { \
142 | abort(); \
143 | } \
144 | } while (0)
145 | #define GWS_DNOT_REACHED() abort()
146 |
147 | #else
148 |
149 | #define GWS_DCHECK(__CONDITION__)
150 | #define GWS_DNOT_REACHED()
151 |
152 | #endif
153 |
154 | #endif
155 |
156 | NS_ASSUME_NONNULL_BEGIN
157 |
158 | /**
159 | * GCDWebServer internal constants and APIs.
160 | */
161 |
162 | #define kGCDWebServerDefaultMimeType @"application/octet-stream"
163 | #define kGCDWebServerErrorDomain @"GCDWebServerErrorDomain"
164 |
165 | static inline BOOL GCDWebServerIsValidByteRange(NSRange range) {
166 | return ((range.location != NSUIntegerMax) || (range.length > 0));
167 | }
168 |
169 | static inline NSError* GCDWebServerMakePosixError(int code) {
170 | return [NSError errorWithDomain:NSPOSIXErrorDomain code:code userInfo:@{NSLocalizedDescriptionKey : (NSString*)[NSString stringWithUTF8String:strerror(code)]}];
171 | }
172 |
173 | extern void GCDWebServerInitializeFunctions(void);
174 | extern NSString* _Nullable GCDWebServerNormalizeHeaderValue(NSString* _Nullable value);
175 | extern NSString* _Nullable GCDWebServerTruncateHeaderValue(NSString* _Nullable value);
176 | extern NSString* _Nullable GCDWebServerExtractHeaderValueParameter(NSString* _Nullable value, NSString* attribute);
177 | extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
178 | extern BOOL GCDWebServerIsTextContentType(NSString* type);
179 | extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType);
180 | extern NSString* GCDWebServerComputeMD5Digest(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2);
181 | extern NSString* GCDWebServerStringFromSockAddr(const struct sockaddr* addr, BOOL includeService);
182 |
183 | @interface GCDWebServerConnection ()
184 | - (instancetype)initWithServer:(GCDWebServer*)server localAddress:(NSData*)localAddress remoteAddress:(NSData*)remoteAddress socket:(CFSocketNativeHandle)socket;
185 | @end
186 |
187 | @interface GCDWebServer ()
188 | @property(nonatomic, readonly) NSMutableArray* handlers;
189 | @property(nonatomic, readonly, nullable) NSString* serverName;
190 | @property(nonatomic, readonly, nullable) NSString* authenticationRealm;
191 | @property(nonatomic, readonly, nullable) NSMutableDictionary* authenticationBasicAccounts;
192 | @property(nonatomic, readonly, nullable) NSMutableDictionary* authenticationDigestAccounts;
193 | @property(nonatomic, readonly) BOOL shouldAutomaticallyMapHEADToGET;
194 | @property(nonatomic, readonly) dispatch_queue_priority_t dispatchQueuePriority;
195 | - (void)willStartConnection:(GCDWebServerConnection*)connection;
196 | - (void)didEndConnection:(GCDWebServerConnection*)connection;
197 | @end
198 |
199 | @interface GCDWebServerHandler : NSObject
200 | @property(nonatomic, readonly) GCDWebServerMatchBlock matchBlock;
201 | @property(nonatomic, readonly) GCDWebServerAsyncProcessBlock asyncProcessBlock;
202 | @end
203 |
204 | @interface GCDWebServerRequest ()
205 | @property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
206 | @property(nonatomic) NSData* localAddressData;
207 | @property(nonatomic) NSData* remoteAddressData;
208 | - (void)prepareForWriting;
209 | - (BOOL)performOpen:(NSError**)error;
210 | - (BOOL)performWriteData:(NSData*)data error:(NSError**)error;
211 | - (BOOL)performClose:(NSError**)error;
212 | - (void)setAttribute:(nullable id)attribute forKey:(NSString*)key;
213 | @end
214 |
215 | @interface GCDWebServerResponse ()
216 | @property(nonatomic, readonly) NSDictionary* additionalHeaders;
217 | @property(nonatomic, readonly) BOOL usesChunkedTransferEncoding;
218 | - (void)prepareForReading;
219 | - (BOOL)performOpen:(NSError**)error;
220 | - (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
221 | - (void)performClose;
222 | @end
223 |
224 | NS_ASSUME_NONNULL_END
225 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * Attribute key to retrieve an NSArray containing NSStrings from a GCDWebServerRequest
34 | * with the contents of any regular expression captures done on the request path.
35 | *
36 | * @warning This attribute will only be set on the request if adding a handler using
37 | * -addHandlerForMethod:pathRegex:requestClass:processBlock:.
38 | */
39 | extern NSString* const GCDWebServerRequestAttribute_RegexCaptures;
40 |
41 | /**
42 | * This protocol is used by the GCDWebServerConnection to communicate with
43 | * the GCDWebServerRequest and write the received HTTP body data.
44 | *
45 | * Note that multiple GCDWebServerBodyWriter objects can be chained together
46 | * internally e.g. to automatically decode gzip encoded content before
47 | * passing it on to the GCDWebServerRequest.
48 | *
49 | * @warning These methods can be called on any GCD thread.
50 | */
51 | @protocol GCDWebServerBodyWriter
52 |
53 | /**
54 | * This method is called before any body data is received.
55 | *
56 | * It should return YES on success or NO on failure and set the "error" argument
57 | * which is guaranteed to be non-NULL.
58 | */
59 | - (BOOL)open:(NSError**)error;
60 |
61 | /**
62 | * This method is called whenever body data has been received.
63 | *
64 | * It should return YES on success or NO on failure and set the "error" argument
65 | * which is guaranteed to be non-NULL.
66 | */
67 | - (BOOL)writeData:(NSData*)data error:(NSError**)error;
68 |
69 | /**
70 | * This method is called after all body data has been received.
71 | *
72 | * It should return YES on success or NO on failure and set the "error" argument
73 | * which is guaranteed to be non-NULL.
74 | */
75 | - (BOOL)close:(NSError**)error;
76 |
77 | @end
78 |
79 | /**
80 | * The GCDWebServerRequest class is instantiated by the GCDWebServerConnection
81 | * after the HTTP headers have been received. Each instance wraps a single HTTP
82 | * request. If a body is present, the methods from the GCDWebServerBodyWriter
83 | * protocol will be called by the GCDWebServerConnection to receive it.
84 | *
85 | * The default implementation of the GCDWebServerBodyWriter protocol on the class
86 | * simply ignores the body data.
87 | *
88 | * @warning GCDWebServerRequest instances can be created and used on any GCD thread.
89 | */
90 | @interface GCDWebServerRequest : NSObject
91 |
92 | /**
93 | * Returns the HTTP method for the request.
94 | */
95 | @property(nonatomic, readonly) NSString* method;
96 |
97 | /**
98 | * Returns the URL for the request.
99 | */
100 | @property(nonatomic, readonly) NSURL* URL;
101 |
102 | /**
103 | * Returns the HTTP headers for the request.
104 | */
105 | @property(nonatomic, readonly) NSDictionary* headers;
106 |
107 | /**
108 | * Returns the path component of the URL for the request.
109 | */
110 | @property(nonatomic, readonly) NSString* path;
111 |
112 | /**
113 | * Returns the parsed and unescaped query component of the URL for the request.
114 | *
115 | * @warning This property will be nil if there is no query in the URL.
116 | */
117 | @property(nonatomic, readonly, nullable) NSDictionary* query;
118 |
119 | /**
120 | * Returns the content type for the body of the request parsed from the
121 | * "Content-Type" header.
122 | *
123 | * This property will be nil if the request has no body or set to
124 | * "application/octet-stream" if a body is present but there was no
125 | * "Content-Type" header.
126 | */
127 | @property(nonatomic, readonly, nullable) NSString* contentType;
128 |
129 | /**
130 | * Returns the content length for the body of the request parsed from the
131 | * "Content-Length" header.
132 | *
133 | * This property will be set to "NSUIntegerMax" if the request has no body or
134 | * if there is a body but no "Content-Length" header, typically because
135 | * chunked transfer encoding is used.
136 | */
137 | @property(nonatomic, readonly) NSUInteger contentLength;
138 |
139 | /**
140 | * Returns the parsed "If-Modified-Since" header or nil if absent or malformed.
141 | */
142 | @property(nonatomic, readonly, nullable) NSDate* ifModifiedSince;
143 |
144 | /**
145 | * Returns the parsed "If-None-Match" header or nil if absent or malformed.
146 | */
147 | @property(nonatomic, readonly, nullable) NSString* ifNoneMatch;
148 |
149 | /**
150 | * Returns the parsed "Range" header or (NSUIntegerMax, 0) if absent or malformed.
151 | * The range will be set to (offset, length) if expressed from the beginning
152 | * of the entity body, or (NSUIntegerMax, length) if expressed from its end.
153 | */
154 | @property(nonatomic, readonly) NSRange byteRange;
155 |
156 | /**
157 | * Returns YES if the client supports gzip content encoding according to the
158 | * "Accept-Encoding" header.
159 | */
160 | @property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
161 |
162 | /**
163 | * Returns the address of the local peer (i.e. server) for the request
164 | * as a raw "struct sockaddr".
165 | */
166 | @property(nonatomic, readonly) NSData* localAddressData;
167 |
168 | /**
169 | * Returns the address of the local peer (i.e. server) for the request
170 | * as a string.
171 | */
172 | @property(nonatomic, readonly) NSString* localAddressString;
173 |
174 | /**
175 | * Returns the address of the remote peer (i.e. client) for the request
176 | * as a raw "struct sockaddr".
177 | */
178 | @property(nonatomic, readonly) NSData* remoteAddressData;
179 |
180 | /**
181 | * Returns the address of the remote peer (i.e. client) for the request
182 | * as a string.
183 | */
184 | @property(nonatomic, readonly) NSString* remoteAddressString;
185 |
186 | /**
187 | * This method is the designated initializer for the class.
188 | */
189 | - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(nullable NSDictionary*)query;
190 |
191 | /**
192 | * Convenience method that checks if the contentType property is defined.
193 | */
194 | - (BOOL)hasBody;
195 |
196 | /**
197 | * Convenience method that checks if the byteRange property is defined.
198 | */
199 | - (BOOL)hasByteRange;
200 |
201 | /**
202 | * Retrieves an attribute associated with this request using the given key.
203 | *
204 | * @return The attribute value for the key.
205 | */
206 | - (nullable id)attributeForKey:(NSString*)key;
207 |
208 | @end
209 |
210 | NS_ASSUME_NONNULL_END
211 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 | NSString* const GCDWebServerRequestAttribute_RegexCaptures = @"GCDWebServerRequestAttribute_RegexCaptures";
37 |
38 | #define kZlibErrorDomain @"ZlibErrorDomain"
39 | #define kGZipInitialBufferSize (256 * 1024)
40 |
41 | @interface GCDWebServerBodyDecoder : NSObject
42 | @end
43 |
44 | @interface GCDWebServerGZipDecoder : GCDWebServerBodyDecoder
45 | @end
46 |
47 | @implementation GCDWebServerBodyDecoder {
48 | GCDWebServerRequest* __unsafe_unretained _request;
49 | id __unsafe_unretained _writer;
50 | }
51 |
52 | - (instancetype)initWithRequest:(GCDWebServerRequest* _Nonnull)request writer:(id _Nonnull)writer {
53 | if ((self = [super init])) {
54 | _request = request;
55 | _writer = writer;
56 | }
57 | return self;
58 | }
59 |
60 | - (BOOL)open:(NSError**)error {
61 | return [_writer open:error];
62 | }
63 |
64 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
65 | return [_writer writeData:data error:error];
66 | }
67 |
68 | - (BOOL)close:(NSError**)error {
69 | return [_writer close:error];
70 | }
71 |
72 | @end
73 |
74 | @implementation GCDWebServerGZipDecoder {
75 | z_stream _stream;
76 | BOOL _finished;
77 | }
78 |
79 | - (BOOL)open:(NSError**)error {
80 | int result = inflateInit2(&_stream, 15 + 16);
81 | if (result != Z_OK) {
82 | if (error) {
83 | *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
84 | }
85 | return NO;
86 | }
87 | if (![super open:error]) {
88 | inflateEnd(&_stream);
89 | return NO;
90 | }
91 | return YES;
92 | }
93 |
94 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
95 | GWS_DCHECK(!_finished);
96 | _stream.next_in = (Bytef*)data.bytes;
97 | _stream.avail_in = (uInt)data.length;
98 | NSMutableData* decodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
99 | if (decodedData == nil) {
100 | GWS_DNOT_REACHED();
101 | return NO;
102 | }
103 | NSUInteger length = 0;
104 | while (1) {
105 | NSUInteger maxLength = decodedData.length - length;
106 | _stream.next_out = (Bytef*)((char*)decodedData.mutableBytes + length);
107 | _stream.avail_out = (uInt)maxLength;
108 | int result = inflate(&_stream, Z_NO_FLUSH);
109 | if ((result != Z_OK) && (result != Z_STREAM_END)) {
110 | if (error) {
111 | *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
112 | }
113 | return NO;
114 | }
115 | length += maxLength - _stream.avail_out;
116 | if (_stream.avail_out > 0) {
117 | if (result == Z_STREAM_END) {
118 | _finished = YES;
119 | }
120 | break;
121 | }
122 | decodedData.length = 2 * decodedData.length; // zlib has used all the output buffer so resize it and try again in case more data is available
123 | }
124 | decodedData.length = length;
125 | BOOL success = length ? [super writeData:decodedData error:error] : YES; // No need to call writer if we have no data yet
126 | return success;
127 | }
128 |
129 | - (BOOL)close:(NSError**)error {
130 | GWS_DCHECK(_finished);
131 | inflateEnd(&_stream);
132 | return [super close:error];
133 | }
134 |
135 | @end
136 |
137 | @implementation GCDWebServerRequest {
138 | BOOL _opened;
139 | NSMutableArray* _decoders;
140 | id __unsafe_unretained _writer;
141 | NSMutableDictionary* _attributes;
142 | }
143 |
144 | - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
145 | if ((self = [super init])) {
146 | _method = [method copy];
147 | _URL = url;
148 | _headers = headers;
149 | _path = [path copy];
150 | _query = query;
151 |
152 | _contentType = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Content-Type"]);
153 | _usesChunkedTransferEncoding = [GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Transfer-Encoding"]) isEqualToString:@"chunked"];
154 | NSString* lengthHeader = [_headers objectForKey:@"Content-Length"];
155 | if (lengthHeader) {
156 | NSInteger length = [lengthHeader integerValue];
157 | if (_usesChunkedTransferEncoding || (length < 0)) {
158 | GWS_LOG_WARNING(@"Invalid 'Content-Length' header '%@' for '%@' request on \"%@\"", lengthHeader, _method, _URL);
159 | GWS_DNOT_REACHED();
160 | return nil;
161 | }
162 | _contentLength = length;
163 | if (_contentType == nil) {
164 | _contentType = kGCDWebServerDefaultMimeType;
165 | }
166 | } else if (_usesChunkedTransferEncoding) {
167 | if (_contentType == nil) {
168 | _contentType = kGCDWebServerDefaultMimeType;
169 | }
170 | _contentLength = NSUIntegerMax;
171 | } else {
172 | if (_contentType) {
173 | GWS_LOG_WARNING(@"Ignoring 'Content-Type' header for '%@' request on \"%@\"", _method, _URL);
174 | _contentType = nil; // Content-Type without Content-Length or chunked-encoding doesn't make sense
175 | }
176 | _contentLength = NSUIntegerMax;
177 | }
178 |
179 | NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"];
180 | if (modifiedHeader) {
181 | _ifModifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy];
182 | }
183 | _ifNoneMatch = [_headers objectForKey:@"If-None-Match"];
184 |
185 | _byteRange = NSMakeRange(NSUIntegerMax, 0);
186 | NSString* rangeHeader = GCDWebServerNormalizeHeaderValue([_headers objectForKey:@"Range"]);
187 | if (rangeHeader) {
188 | if ([rangeHeader hasPrefix:@"bytes="]) {
189 | NSArray* components = [[rangeHeader substringFromIndex:6] componentsSeparatedByString:@","];
190 | if (components.count == 1) {
191 | components = [(NSString*)[components firstObject] componentsSeparatedByString:@"-"];
192 | if (components.count == 2) {
193 | NSString* startString = [components objectAtIndex:0];
194 | NSInteger startValue = [startString integerValue];
195 | NSString* endString = [components objectAtIndex:1];
196 | NSInteger endValue = [endString integerValue];
197 | if (startString.length && (startValue >= 0) && endString.length && (endValue >= startValue)) { // The second 500 bytes: "500-999"
198 | _byteRange.location = startValue;
199 | _byteRange.length = endValue - startValue + 1;
200 | } else if (startString.length && (startValue >= 0)) { // The bytes after 9500 bytes: "9500-"
201 | _byteRange.location = startValue;
202 | _byteRange.length = NSUIntegerMax;
203 | } else if (endString.length && (endValue > 0)) { // The final 500 bytes: "-500"
204 | _byteRange.location = NSUIntegerMax;
205 | _byteRange.length = endValue;
206 | }
207 | }
208 | }
209 | }
210 | if ((_byteRange.location == NSUIntegerMax) && (_byteRange.length == 0)) { // Ignore "Range" header if syntactically invalid
211 | GWS_LOG_WARNING(@"Failed to parse 'Range' header \"%@\" for url: %@", rangeHeader, url);
212 | }
213 | }
214 |
215 | if ([[_headers objectForKey:@"Accept-Encoding"] rangeOfString:@"gzip"].location != NSNotFound) {
216 | _acceptsGzipContentEncoding = YES;
217 | }
218 |
219 | _decoders = [[NSMutableArray alloc] init];
220 | _attributes = [[NSMutableDictionary alloc] init];
221 | }
222 | return self;
223 | }
224 |
225 | - (BOOL)hasBody {
226 | return _contentType ? YES : NO;
227 | }
228 |
229 | - (BOOL)hasByteRange {
230 | return GCDWebServerIsValidByteRange(_byteRange);
231 | }
232 |
233 | - (id)attributeForKey:(NSString*)key {
234 | return [_attributes objectForKey:key];
235 | }
236 |
237 | - (BOOL)open:(NSError**)error {
238 | return YES;
239 | }
240 |
241 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
242 | return YES;
243 | }
244 |
245 | - (BOOL)close:(NSError**)error {
246 | return YES;
247 | }
248 |
249 | - (void)prepareForWriting {
250 | _writer = self;
251 | if ([GCDWebServerNormalizeHeaderValue([self.headers objectForKey:@"Content-Encoding"]) isEqualToString:@"gzip"]) {
252 | GCDWebServerGZipDecoder* decoder = [[GCDWebServerGZipDecoder alloc] initWithRequest:self writer:_writer];
253 | [_decoders addObject:decoder];
254 | _writer = decoder;
255 | }
256 | }
257 |
258 | - (BOOL)performOpen:(NSError**)error {
259 | GWS_DCHECK(_contentType);
260 | GWS_DCHECK(_writer);
261 | if (_opened) {
262 | GWS_DNOT_REACHED();
263 | return NO;
264 | }
265 | _opened = YES;
266 | return [_writer open:error];
267 | }
268 |
269 | - (BOOL)performWriteData:(NSData*)data error:(NSError**)error {
270 | GWS_DCHECK(_opened);
271 | return [_writer writeData:data error:error];
272 | }
273 |
274 | - (BOOL)performClose:(NSError**)error {
275 | GWS_DCHECK(_opened);
276 | return [_writer close:error];
277 | }
278 |
279 | - (void)setAttribute:(id)attribute forKey:(NSString*)key {
280 | [_attributes setValue:attribute forKey:key];
281 | }
282 |
283 | - (NSString*)localAddressString {
284 | return GCDWebServerStringFromSockAddr(_localAddressData.bytes, YES);
285 | }
286 |
287 | - (NSString*)remoteAddressString {
288 | return GCDWebServerStringFromSockAddr(_remoteAddressData.bytes, YES);
289 | }
290 |
291 | - (NSString*)description {
292 | NSMutableString* description = [NSMutableString stringWithFormat:@"%@ %@", _method, _path];
293 | for (NSString* argument in [[_query allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
294 | [description appendFormat:@"\n %@ = %@", argument, [_query objectForKey:argument]];
295 | }
296 | [description appendString:@"\n"];
297 | for (NSString* header in [[_headers allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
298 | [description appendFormat:@"\n%@: %@", header, [_headers objectForKey:header]];
299 | }
300 | return description;
301 | }
302 |
303 | @end
304 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerBodyReaderCompletionBlock is passed by GCDWebServer to the
34 | * GCDWebServerBodyReader object when reading data from it asynchronously.
35 | */
36 | typedef void (^GCDWebServerBodyReaderCompletionBlock)(NSData* _Nullable data, NSError* _Nullable error);
37 |
38 | /**
39 | * This protocol is used by the GCDWebServerConnection to communicate with
40 | * the GCDWebServerResponse and read the HTTP body data to send.
41 | *
42 | * Note that multiple GCDWebServerBodyReader objects can be chained together
43 | * internally e.g. to automatically apply gzip encoding to the content before
44 | * passing it on to the GCDWebServerResponse.
45 | *
46 | * @warning These methods can be called on any GCD thread.
47 | */
48 | @protocol GCDWebServerBodyReader
49 |
50 | @required
51 |
52 | /**
53 | * This method is called before any body data is sent.
54 | *
55 | * It should return YES on success or NO on failure and set the "error" argument
56 | * which is guaranteed to be non-NULL.
57 | */
58 | - (BOOL)open:(NSError**)error;
59 |
60 | /**
61 | * This method is called whenever body data is sent.
62 | *
63 | * It should return a non-empty NSData if there is body data available,
64 | * or an empty NSData there is no more body data, or nil on error and set
65 | * the "error" argument which is guaranteed to be non-NULL.
66 | */
67 | - (nullable NSData*)readData:(NSError**)error;
68 |
69 | /**
70 | * This method is called after all body data has been sent.
71 | */
72 | - (void)close;
73 |
74 | @optional
75 |
76 | /**
77 | * If this method is implemented, it will be preferred over -readData:.
78 | *
79 | * It must call the passed block when data is available, passing a non-empty
80 | * NSData if there is body data available, or an empty NSData there is no more
81 | * body data, or nil on error and pass an NSError along.
82 | */
83 | - (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block;
84 |
85 | @end
86 |
87 | /**
88 | * The GCDWebServerResponse class is used to wrap a single HTTP response.
89 | * It is instantiated by the handler of the GCDWebServer that handled the request.
90 | * If a body is present, the methods from the GCDWebServerBodyReader protocol
91 | * will be called by the GCDWebServerConnection to send it.
92 | *
93 | * The default implementation of the GCDWebServerBodyReader protocol
94 | * on the class simply returns an empty body.
95 | *
96 | * @warning GCDWebServerResponse instances can be created and used on any GCD thread.
97 | */
98 | @interface GCDWebServerResponse : NSObject
99 |
100 | /**
101 | * Sets the content type for the body of the response.
102 | *
103 | * The default value is nil i.e. the response has no body.
104 | *
105 | * @warning This property must be set if a body is present.
106 | */
107 | @property(nonatomic, copy, nullable) NSString* contentType;
108 |
109 | /**
110 | * Sets the content length for the body of the response. If a body is present
111 | * but this property is set to "NSUIntegerMax", this means the length of the body
112 | * cannot be known ahead of time. Chunked transfer encoding will be
113 | * automatically enabled by the GCDWebServerConnection to comply with HTTP/1.1
114 | * specifications.
115 | *
116 | * The default value is "NSUIntegerMax" i.e. the response has no body or its length
117 | * is undefined.
118 | */
119 | @property(nonatomic) NSUInteger contentLength;
120 |
121 | /**
122 | * Sets the HTTP status code for the response.
123 | *
124 | * The default value is 200 i.e. "OK".
125 | */
126 | @property(nonatomic) NSInteger statusCode;
127 |
128 | /**
129 | * Sets the caching hint for the response using the "Cache-Control" header.
130 | * This value is expressed in seconds.
131 | *
132 | * The default value is 0 i.e. "no-cache".
133 | */
134 | @property(nonatomic) NSUInteger cacheControlMaxAge;
135 |
136 | /**
137 | * Sets the last modified date for the response using the "Last-Modified" header.
138 | *
139 | * The default value is nil.
140 | */
141 | @property(nonatomic, nullable) NSDate* lastModifiedDate;
142 |
143 | /**
144 | * Sets the ETag for the response using the "ETag" header.
145 | *
146 | * The default value is nil.
147 | */
148 | @property(nonatomic, copy, nullable) NSString* eTag;
149 |
150 | /**
151 | * Enables gzip encoding for the response body.
152 | *
153 | * The default value is NO.
154 | *
155 | * @warning Enabling gzip encoding will remove any "Content-Length" header
156 | * since the length of the body is not known anymore. The client will still
157 | * be able to determine the body length when connection is closed per
158 | * HTTP/1.1 specifications.
159 | */
160 | @property(nonatomic, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled;
161 |
162 | /**
163 | * Creates an empty response.
164 | */
165 | + (instancetype)response;
166 |
167 | /**
168 | * This method is the designated initializer for the class.
169 | */
170 | - (instancetype)init;
171 |
172 | /**
173 | * Sets an additional HTTP header on the response.
174 | * Pass a nil value to remove an additional header.
175 | *
176 | * @warning Do not attempt to override the primary headers used
177 | * by GCDWebServerResponse like "Content-Type", "ETag", etc...
178 | */
179 | - (void)setValue:(nullable NSString*)value forAdditionalHeader:(NSString*)header;
180 |
181 | /**
182 | * Convenience method that checks if the contentType property is defined.
183 | */
184 | - (BOOL)hasBody;
185 |
186 | @end
187 |
188 | @interface GCDWebServerResponse (Extensions)
189 |
190 | /**
191 | * Creates a empty response with a specific HTTP status code.
192 | */
193 | + (instancetype)responseWithStatusCode:(NSInteger)statusCode;
194 |
195 | /**
196 | * Creates an HTTP redirect response to a new URL.
197 | */
198 | + (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
199 |
200 | /**
201 | * Initializes an empty response with a specific HTTP status code.
202 | */
203 | - (instancetype)initWithStatusCode:(NSInteger)statusCode;
204 |
205 | /**
206 | * Initializes an HTTP redirect response to a new URL.
207 | */
208 | - (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
209 |
210 | @end
211 |
212 | NS_ASSUME_NONNULL_END
213 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 kZlibErrorDomain @"ZlibErrorDomain"
37 | #define kGZipInitialBufferSize (256 * 1024)
38 |
39 | @interface GCDWebServerBodyEncoder : NSObject
40 | @end
41 |
42 | @interface GCDWebServerGZipEncoder : GCDWebServerBodyEncoder
43 | @end
44 |
45 | @implementation GCDWebServerBodyEncoder {
46 | GCDWebServerResponse* __unsafe_unretained _response;
47 | id __unsafe_unretained _reader;
48 | }
49 |
50 | - (instancetype)initWithResponse:(GCDWebServerResponse* _Nonnull)response reader:(id _Nonnull)reader {
51 | if ((self = [super init])) {
52 | _response = response;
53 | _reader = reader;
54 | }
55 | return self;
56 | }
57 |
58 | - (BOOL)open:(NSError**)error {
59 | return [_reader open:error];
60 | }
61 |
62 | - (NSData*)readData:(NSError**)error {
63 | return [_reader readData:error];
64 | }
65 |
66 | - (void)close {
67 | [_reader close];
68 | }
69 |
70 | @end
71 |
72 | @implementation GCDWebServerGZipEncoder {
73 | z_stream _stream;
74 | BOOL _finished;
75 | }
76 |
77 | - (instancetype)initWithResponse:(GCDWebServerResponse* _Nonnull)response reader:(id _Nonnull)reader {
78 | if ((self = [super initWithResponse:response reader:reader])) {
79 | response.contentLength = NSUIntegerMax; // Make sure "Content-Length" header is not set since we don't know it
80 | [response setValue:@"gzip" forAdditionalHeader:@"Content-Encoding"];
81 | }
82 | return self;
83 | }
84 |
85 | - (BOOL)open:(NSError**)error {
86 | int result = deflateInit2(&_stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
87 | if (result != Z_OK) {
88 | if (error) {
89 | *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
90 | }
91 | return NO;
92 | }
93 | if (![super open:error]) {
94 | deflateEnd(&_stream);
95 | return NO;
96 | }
97 | return YES;
98 | }
99 |
100 | - (NSData*)readData:(NSError**)error {
101 | NSMutableData* encodedData;
102 | if (_finished) {
103 | encodedData = [[NSMutableData alloc] init];
104 | } else {
105 | encodedData = [[NSMutableData alloc] initWithLength:kGZipInitialBufferSize];
106 | if (encodedData == nil) {
107 | GWS_DNOT_REACHED();
108 | return nil;
109 | }
110 | NSUInteger length = 0;
111 | do {
112 | NSData* data = [super readData:error];
113 | if (data == nil) {
114 | return nil;
115 | }
116 | _stream.next_in = (Bytef*)data.bytes;
117 | _stream.avail_in = (uInt)data.length;
118 | while (1) {
119 | NSUInteger maxLength = encodedData.length - length;
120 | _stream.next_out = (Bytef*)((char*)encodedData.mutableBytes + length);
121 | _stream.avail_out = (uInt)maxLength;
122 | int result = deflate(&_stream, data.length ? Z_NO_FLUSH : Z_FINISH);
123 | if (result == Z_STREAM_END) {
124 | _finished = YES;
125 | } else if (result != Z_OK) {
126 | if (error) {
127 | *error = [NSError errorWithDomain:kZlibErrorDomain code:result userInfo:nil];
128 | }
129 | return nil;
130 | }
131 | length += maxLength - _stream.avail_out;
132 | if (_stream.avail_out > 0) {
133 | break;
134 | }
135 | encodedData.length = 2 * encodedData.length; // zlib has used all the output buffer so resize it and try again in case more data is available
136 | }
137 | GWS_DCHECK(_stream.avail_in == 0);
138 | } while (length == 0); // Make sure we don't return an empty NSData if not in finished state
139 | encodedData.length = length;
140 | }
141 | return encodedData;
142 | }
143 |
144 | - (void)close {
145 | deflateEnd(&_stream);
146 | [super close];
147 | }
148 |
149 | @end
150 |
151 | @implementation GCDWebServerResponse {
152 | BOOL _opened;
153 | NSMutableArray* _encoders;
154 | id __unsafe_unretained _reader;
155 | }
156 |
157 | + (instancetype)response {
158 | return [(GCDWebServerResponse*)[[self class] alloc] init];
159 | }
160 |
161 | - (instancetype)init {
162 | if ((self = [super init])) {
163 | _contentType = nil;
164 | _contentLength = NSUIntegerMax;
165 | _statusCode = kGCDWebServerHTTPStatusCode_OK;
166 | _cacheControlMaxAge = 0;
167 | _additionalHeaders = [[NSMutableDictionary alloc] init];
168 | _encoders = [[NSMutableArray alloc] init];
169 | }
170 | return self;
171 | }
172 |
173 | - (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header {
174 | [_additionalHeaders setValue:value forKey:header];
175 | }
176 |
177 | - (BOOL)hasBody {
178 | return _contentType ? YES : NO;
179 | }
180 |
181 | - (BOOL)usesChunkedTransferEncoding {
182 | return (_contentType != nil) && (_contentLength == NSUIntegerMax);
183 | }
184 |
185 | - (BOOL)open:(NSError**)error {
186 | return YES;
187 | }
188 |
189 | - (NSData*)readData:(NSError**)error {
190 | return [NSData data];
191 | }
192 |
193 | - (void)close {
194 | ;
195 | }
196 |
197 | - (void)prepareForReading {
198 | _reader = self;
199 | if (_gzipContentEncodingEnabled) {
200 | GCDWebServerGZipEncoder* encoder = [[GCDWebServerGZipEncoder alloc] initWithResponse:self reader:_reader];
201 | [_encoders addObject:encoder];
202 | _reader = encoder;
203 | }
204 | }
205 |
206 | - (BOOL)performOpen:(NSError**)error {
207 | GWS_DCHECK(_contentType);
208 | GWS_DCHECK(_reader);
209 | if (_opened) {
210 | GWS_DNOT_REACHED();
211 | return NO;
212 | }
213 | _opened = YES;
214 | return [_reader open:error];
215 | }
216 |
217 | - (void)performReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
218 | GWS_DCHECK(_opened);
219 | if ([_reader respondsToSelector:@selector(asyncReadDataWithCompletion:)]) {
220 | [_reader asyncReadDataWithCompletion:[block copy]];
221 | } else {
222 | NSError* error = nil;
223 | NSData* data = [_reader readData:&error];
224 | block(data, error);
225 | }
226 | }
227 |
228 | - (void)performClose {
229 | GWS_DCHECK(_opened);
230 | [_reader close];
231 | }
232 |
233 | - (NSString*)description {
234 | NSMutableString* description = [NSMutableString stringWithFormat:@"Status Code = %i", (int)_statusCode];
235 | if (_contentType) {
236 | [description appendFormat:@"\nContent Type = %@", _contentType];
237 | }
238 | if (_contentLength != NSUIntegerMax) {
239 | [description appendFormat:@"\nContent Length = %lu", (unsigned long)_contentLength];
240 | }
241 | [description appendFormat:@"\nCache Control Max Age = %lu", (unsigned long)_cacheControlMaxAge];
242 | if (_lastModifiedDate) {
243 | [description appendFormat:@"\nLast Modified Date = %@", _lastModifiedDate];
244 | }
245 | if (_eTag) {
246 | [description appendFormat:@"\nETag = %@", _eTag];
247 | }
248 | if (_additionalHeaders.count) {
249 | [description appendString:@"\n"];
250 | for (NSString* header in [[_additionalHeaders allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
251 | [description appendFormat:@"\n%@: %@", header, [_additionalHeaders objectForKey:header]];
252 | }
253 | }
254 | return description;
255 | }
256 |
257 | @end
258 |
259 | @implementation GCDWebServerResponse (Extensions)
260 |
261 | + (instancetype)responseWithStatusCode:(NSInteger)statusCode {
262 | return [(GCDWebServerResponse*)[self alloc] initWithStatusCode:statusCode];
263 | }
264 |
265 | + (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent {
266 | return [(GCDWebServerResponse*)[self alloc] initWithRedirect:location permanent:permanent];
267 | }
268 |
269 | - (instancetype)initWithStatusCode:(NSInteger)statusCode {
270 | if ((self = [self init])) {
271 | self.statusCode = statusCode;
272 | }
273 | return self;
274 | }
275 |
276 | - (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent {
277 | if ((self = [self init])) {
278 | self.statusCode = permanent ? kGCDWebServerHTTPStatusCode_MovedPermanently : kGCDWebServerHTTPStatusCode_TemporaryRedirect;
279 | [self setValue:[location absoluteString] forAdditionalHeader:@"Location"];
280 | }
281 | return self;
282 | }
283 |
284 | @end
285 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServerRequest.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerDataRequest subclass of GCDWebServerRequest stores the body
34 | * of the HTTP request in memory.
35 | */
36 | @interface GCDWebServerDataRequest : GCDWebServerRequest
37 |
38 | /**
39 | * Returns the data for the request body.
40 | */
41 | @property(nonatomic, readonly) NSData* data;
42 |
43 | @end
44 |
45 | @interface GCDWebServerDataRequest (Extensions)
46 |
47 | /**
48 | * Returns the data for the request body interpreted as text. If the content
49 | * type of the body is not a text one, or if an error occurs, nil is returned.
50 | *
51 | * The text encoding used to interpret the data is extracted from the
52 | * "Content-Type" header or defaults to UTF-8.
53 | */
54 | @property(nonatomic, readonly, nullable) NSString* text;
55 |
56 | /**
57 | * Returns the data for the request body interpreted as a JSON object. If the
58 | * content type of the body is not JSON, or if an error occurs, nil is returned.
59 | */
60 | @property(nonatomic, readonly, nullable) id jsonObject;
61 |
62 | @end
63 |
64 | NS_ASSUME_NONNULL_END
65 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 | @interface GCDWebServerDataRequest ()
35 | @property(nonatomic) NSMutableData* data;
36 | @end
37 |
38 | @implementation GCDWebServerDataRequest {
39 | NSString* _text;
40 | id _jsonObject;
41 | }
42 |
43 | - (BOOL)open:(NSError**)error {
44 | if (self.contentLength != NSUIntegerMax) {
45 | _data = [[NSMutableData alloc] initWithCapacity:self.contentLength];
46 | } else {
47 | _data = [[NSMutableData alloc] init];
48 | }
49 | if (_data == nil) {
50 | if (error) {
51 | *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Failed allocating memory"}];
52 | }
53 | return NO;
54 | }
55 | return YES;
56 | }
57 |
58 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
59 | [_data appendData:data];
60 | return YES;
61 | }
62 |
63 | - (BOOL)close:(NSError**)error {
64 | return YES;
65 | }
66 |
67 | - (NSString*)description {
68 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
69 | if (_data) {
70 | [description appendString:@"\n\n"];
71 | [description appendString:GCDWebServerDescribeData(_data, (NSString*)self.contentType)];
72 | }
73 | return description;
74 | }
75 |
76 | @end
77 |
78 | @implementation GCDWebServerDataRequest (Extensions)
79 |
80 | - (NSString*)text {
81 | if (_text == nil) {
82 | if ([self.contentType hasPrefix:@"text/"]) {
83 | NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
84 | _text = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
85 | } else {
86 | GWS_DNOT_REACHED();
87 | }
88 | }
89 | return _text;
90 | }
91 |
92 | - (id)jsonObject {
93 | if (_jsonObject == nil) {
94 | NSString* mimeType = GCDWebServerTruncateHeaderValue(self.contentType);
95 | if ([mimeType isEqualToString:@"application/json"] || [mimeType isEqualToString:@"text/json"] || [mimeType isEqualToString:@"text/javascript"]) {
96 | _jsonObject = [NSJSONSerialization JSONObjectWithData:_data options:0 error:NULL];
97 | } else {
98 | GWS_DNOT_REACHED();
99 | }
100 | }
101 | return _jsonObject;
102 | }
103 |
104 | @end
105 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServerRequest.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerFileRequest subclass of GCDWebServerRequest stores the body
34 | * of the HTTP request to a file on disk.
35 | */
36 | @interface GCDWebServerFileRequest : GCDWebServerRequest
37 |
38 | /**
39 | * Returns the path to the temporary file containing the request body.
40 | *
41 | * @warning This temporary file will be automatically deleted when the
42 | * GCDWebServerFileRequest is deallocated. If you want to preserve this file,
43 | * you must move it to a different location beforehand.
44 | */
45 | @property(nonatomic, readonly) NSString* temporaryPath;
46 |
47 | @end
48 |
49 | NS_ASSUME_NONNULL_END
50 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 GCDWebServerFileRequest {
35 | int _file;
36 | }
37 |
38 | - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
39 | if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
40 | _temporaryPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
41 | }
42 | return self;
43 | }
44 |
45 | - (void)dealloc {
46 | unlink([_temporaryPath fileSystemRepresentation]);
47 | }
48 |
49 | - (BOOL)open:(NSError**)error {
50 | _file = open([_temporaryPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
51 | if (_file <= 0) {
52 | if (error) {
53 | *error = GCDWebServerMakePosixError(errno);
54 | }
55 | return NO;
56 | }
57 | return YES;
58 | }
59 |
60 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
61 | if (write(_file, data.bytes, data.length) != (ssize_t)data.length) {
62 | if (error) {
63 | *error = GCDWebServerMakePosixError(errno);
64 | }
65 | return NO;
66 | }
67 | return YES;
68 | }
69 |
70 | - (BOOL)close:(NSError**)error {
71 | if (close(_file) < 0) {
72 | if (error) {
73 | *error = GCDWebServerMakePosixError(errno);
74 | }
75 | return NO;
76 | }
77 | #ifdef __GCDWEBSERVER_ENABLE_TESTING__
78 | NSString* creationDateHeader = [self.headers objectForKey:@"X-GCDWebServer-CreationDate"];
79 | if (creationDateHeader) {
80 | NSDate* date = GCDWebServerParseISO8601(creationDateHeader);
81 | if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate : date} ofItemAtPath:_temporaryPath error:error]) {
82 | return NO;
83 | }
84 | }
85 | NSString* modifiedDateHeader = [self.headers objectForKey:@"X-GCDWebServer-ModifiedDate"];
86 | if (modifiedDateHeader) {
87 | NSDate* date = GCDWebServerParseRFC822(modifiedDateHeader);
88 | if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate : date} ofItemAtPath:_temporaryPath error:error]) {
89 | return NO;
90 | }
91 | }
92 | #endif
93 | return YES;
94 | }
95 |
96 | - (NSString*)description {
97 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
98 | [description appendFormat:@"\n\n{%@}", _temporaryPath];
99 | return description;
100 | }
101 |
102 | @end
103 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServerRequest.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerMultiPart class is an abstract class that wraps the content
34 | * of a part.
35 | */
36 | @interface GCDWebServerMultiPart : NSObject
37 |
38 | /**
39 | * Returns the control name retrieved from the part headers.
40 | */
41 | @property(nonatomic, readonly) NSString* controlName;
42 |
43 | /**
44 | * Returns the content type retrieved from the part headers or "text/plain"
45 | * if not available (per HTTP specifications).
46 | */
47 | @property(nonatomic, readonly) NSString* contentType;
48 |
49 | /**
50 | * Returns the MIME type component of the content type for the part.
51 | */
52 | @property(nonatomic, readonly) NSString* mimeType;
53 |
54 | @end
55 |
56 | /**
57 | * The GCDWebServerMultiPartArgument subclass of GCDWebServerMultiPart wraps
58 | * the content of a part as data in memory.
59 | */
60 | @interface GCDWebServerMultiPartArgument : GCDWebServerMultiPart
61 |
62 | /**
63 | * Returns the data for the part.
64 | */
65 | @property(nonatomic, readonly) NSData* data;
66 |
67 | /**
68 | * Returns the data for the part interpreted as text. If the content
69 | * type of the part is not a text one, or if an error occurs, nil is returned.
70 | *
71 | * The text encoding used to interpret the data is extracted from the
72 | * "Content-Type" header or defaults to UTF-8.
73 | */
74 | @property(nonatomic, readonly, nullable) NSString* string;
75 |
76 | @end
77 |
78 | /**
79 | * The GCDWebServerMultiPartFile subclass of GCDWebServerMultiPart wraps
80 | * the content of a part as a file on disk.
81 | */
82 | @interface GCDWebServerMultiPartFile : GCDWebServerMultiPart
83 |
84 | /**
85 | * Returns the file name retrieved from the part headers.
86 | */
87 | @property(nonatomic, readonly) NSString* fileName;
88 |
89 | /**
90 | * Returns the path to the temporary file containing the part data.
91 | *
92 | * @warning This temporary file will be automatically deleted when the
93 | * GCDWebServerMultiPartFile is deallocated. If you want to preserve this file,
94 | * you must move it to a different location beforehand.
95 | */
96 | @property(nonatomic, readonly) NSString* temporaryPath;
97 |
98 | @end
99 |
100 | /**
101 | * The GCDWebServerMultiPartFormRequest subclass of GCDWebServerRequest
102 | * parses the body of the HTTP request as a multipart encoded form.
103 | */
104 | @interface GCDWebServerMultiPartFormRequest : GCDWebServerRequest
105 |
106 | /**
107 | * Returns the argument parts from the multipart encoded form as
108 | * name / GCDWebServerMultiPartArgument pairs.
109 | */
110 | @property(nonatomic, readonly) NSArray* arguments;
111 |
112 | /**
113 | * Returns the files parts from the multipart encoded form as
114 | * name / GCDWebServerMultiPartFile pairs.
115 | */
116 | @property(nonatomic, readonly) NSArray* files;
117 |
118 | /**
119 | * Returns the MIME type for multipart encoded forms
120 | * i.e. "multipart/form-data".
121 | */
122 | + (NSString*)mimeType;
123 |
124 | /**
125 | * Returns the first argument for a given control name or nil if not found.
126 | */
127 | - (nullable GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name;
128 |
129 | /**
130 | * Returns the first file for a given control name or nil if not found.
131 | */
132 | - (nullable GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name;
133 |
134 | @end
135 |
136 | NS_ASSUME_NONNULL_END
137 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 | #define kMultiPartBufferSize (256 * 1024)
35 |
36 | typedef enum {
37 | kParserState_Undefined = 0,
38 | kParserState_Start,
39 | kParserState_Headers,
40 | kParserState_Content,
41 | kParserState_End
42 | } ParserState;
43 |
44 | @interface GCDWebServerMIMEStreamParser : NSObject
45 | @end
46 |
47 | static NSData* _newlineData = nil;
48 | static NSData* _newlinesData = nil;
49 | static NSData* _dashNewlineData = nil;
50 |
51 | @implementation GCDWebServerMultiPart
52 |
53 | - (instancetype)initWithControlName:(NSString* _Nonnull)name contentType:(NSString* _Nonnull)type {
54 | if ((self = [super init])) {
55 | _controlName = [name copy];
56 | _contentType = [type copy];
57 | _mimeType = (NSString*)GCDWebServerTruncateHeaderValue(_contentType);
58 | }
59 | return self;
60 | }
61 |
62 | @end
63 |
64 | @implementation GCDWebServerMultiPartArgument
65 |
66 | - (instancetype)initWithControlName:(NSString* _Nonnull)name contentType:(NSString* _Nonnull)type data:(NSData* _Nonnull)data {
67 | if ((self = [super initWithControlName:name contentType:type])) {
68 | _data = data;
69 |
70 | if ([self.contentType hasPrefix:@"text/"]) {
71 | NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
72 | _string = [[NSString alloc] initWithData:_data encoding:GCDWebServerStringEncodingFromCharset(charset)];
73 | }
74 | }
75 | return self;
76 | }
77 |
78 | - (NSString*)description {
79 | return [NSString stringWithFormat:@"<%@ | '%@' | %lu bytes>", [self class], self.mimeType, (unsigned long)_data.length];
80 | }
81 |
82 | @end
83 |
84 | @implementation GCDWebServerMultiPartFile
85 |
86 | - (instancetype)initWithControlName:(NSString* _Nonnull)name contentType:(NSString* _Nonnull)type fileName:(NSString* _Nonnull)fileName temporaryPath:(NSString* _Nonnull)temporaryPath {
87 | if ((self = [super initWithControlName:name contentType:type])) {
88 | _fileName = [fileName copy];
89 | _temporaryPath = [temporaryPath copy];
90 | }
91 | return self;
92 | }
93 |
94 | - (void)dealloc {
95 | unlink([_temporaryPath fileSystemRepresentation]);
96 | }
97 |
98 | - (NSString*)description {
99 | return [NSString stringWithFormat:@"<%@ | '%@' | '%@>'", [self class], self.mimeType, _fileName];
100 | }
101 |
102 | @end
103 |
104 | @implementation GCDWebServerMIMEStreamParser {
105 | NSData* _boundary;
106 | NSString* _defaultcontrolName;
107 | ParserState _state;
108 | NSMutableData* _data;
109 | NSMutableArray* _arguments;
110 | NSMutableArray* _files;
111 |
112 | NSString* _controlName;
113 | NSString* _fileName;
114 | NSString* _contentType;
115 | NSString* _tmpPath;
116 | int _tmpFile;
117 | GCDWebServerMIMEStreamParser* _subParser;
118 | }
119 |
120 | + (void)initialize {
121 | if (_newlineData == nil) {
122 | _newlineData = [[NSData alloc] initWithBytes:"\r\n" length:2];
123 | GWS_DCHECK(_newlineData);
124 | }
125 | if (_newlinesData == nil) {
126 | _newlinesData = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
127 | GWS_DCHECK(_newlinesData);
128 | }
129 | if (_dashNewlineData == nil) {
130 | _dashNewlineData = [[NSData alloc] initWithBytes:"--\r\n" length:4];
131 | GWS_DCHECK(_dashNewlineData);
132 | }
133 | }
134 |
135 | - (instancetype)initWithBoundary:(NSString* _Nonnull)boundary defaultControlName:(NSString* _Nullable)name arguments:(NSMutableArray* _Nonnull)arguments files:(NSMutableArray* _Nonnull)files {
136 | NSData* data = boundary.length ? [[NSString stringWithFormat:@"--%@", boundary] dataUsingEncoding:NSASCIIStringEncoding] : nil;
137 | if (data == nil) {
138 | GWS_DNOT_REACHED();
139 | return nil;
140 | }
141 | if ((self = [super init])) {
142 | _boundary = data;
143 | _defaultcontrolName = name;
144 | _arguments = arguments;
145 | _files = files;
146 | _data = [[NSMutableData alloc] initWithCapacity:kMultiPartBufferSize];
147 | _state = kParserState_Start;
148 | }
149 | return self;
150 | }
151 |
152 | - (void)dealloc {
153 | if (_tmpFile > 0) {
154 | close(_tmpFile);
155 | unlink([_tmpPath fileSystemRepresentation]);
156 | }
157 | }
158 |
159 | // http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2
160 | - (BOOL)_parseData {
161 | BOOL success = YES;
162 |
163 | if (_state == kParserState_Headers) {
164 | NSRange range = [_data rangeOfData:_newlinesData options:0 range:NSMakeRange(0, _data.length)];
165 | if (range.location != NSNotFound) {
166 | _controlName = nil;
167 | _fileName = nil;
168 | _contentType = nil;
169 | _tmpPath = nil;
170 | _subParser = nil;
171 | NSString* headers = [[NSString alloc] initWithData:[_data subdataWithRange:NSMakeRange(0, range.location)] encoding:NSUTF8StringEncoding];
172 | if (headers) {
173 | for (NSString* header in [headers componentsSeparatedByString:@"\r\n"]) {
174 | NSRange subRange = [header rangeOfString:@":"];
175 | if (subRange.location != NSNotFound) {
176 | NSString* name = [header substringToIndex:subRange.location];
177 | NSString* value = [[header substringFromIndex:(subRange.location + subRange.length)] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
178 | if ([name caseInsensitiveCompare:@"Content-Type"] == NSOrderedSame) {
179 | _contentType = GCDWebServerNormalizeHeaderValue(value);
180 | } else if ([name caseInsensitiveCompare:@"Content-Disposition"] == NSOrderedSame) {
181 | NSString* contentDisposition = GCDWebServerNormalizeHeaderValue(value);
182 | if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"form-data"]) {
183 | _controlName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"name");
184 | _fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
185 | } else if ([GCDWebServerTruncateHeaderValue(contentDisposition) isEqualToString:@"file"]) {
186 | _controlName = _defaultcontrolName;
187 | _fileName = GCDWebServerExtractHeaderValueParameter(contentDisposition, @"filename");
188 | }
189 | }
190 | } else {
191 | GWS_DNOT_REACHED();
192 | }
193 | }
194 | if (_contentType == nil) {
195 | _contentType = @"text/plain";
196 | }
197 | } else {
198 | GWS_LOG_ERROR(@"Failed decoding headers in part of 'multipart/form-data'");
199 | GWS_DNOT_REACHED();
200 | }
201 | if (_controlName) {
202 | if ([GCDWebServerTruncateHeaderValue(_contentType) isEqualToString:@"multipart/mixed"]) {
203 | NSString* boundary = GCDWebServerExtractHeaderValueParameter(_contentType, @"boundary");
204 | _subParser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:_controlName arguments:_arguments files:_files];
205 | if (_subParser == nil) {
206 | GWS_DNOT_REACHED();
207 | success = NO;
208 | }
209 | } else if (_fileName) {
210 | NSString* path = [NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]];
211 | _tmpFile = open([path fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
212 | if (_tmpFile > 0) {
213 | _tmpPath = [path copy];
214 | } else {
215 | GWS_DNOT_REACHED();
216 | success = NO;
217 | }
218 | }
219 | } else {
220 | GWS_DNOT_REACHED();
221 | success = NO;
222 | }
223 |
224 | [_data replaceBytesInRange:NSMakeRange(0, range.location + range.length) withBytes:NULL length:0];
225 | _state = kParserState_Content;
226 | }
227 | }
228 |
229 | if ((_state == kParserState_Start) || (_state == kParserState_Content)) {
230 | NSRange range = [_data rangeOfData:_boundary options:0 range:NSMakeRange(0, _data.length)];
231 | if (range.location != NSNotFound) {
232 | NSRange subRange = NSMakeRange(range.location + range.length, _data.length - range.location - range.length);
233 | NSRange subRange1 = [_data rangeOfData:_newlineData options:NSDataSearchAnchored range:subRange];
234 | NSRange subRange2 = [_data rangeOfData:_dashNewlineData options:NSDataSearchAnchored range:subRange];
235 | if ((subRange1.location != NSNotFound) || (subRange2.location != NSNotFound)) {
236 | if (_state == kParserState_Content) {
237 | const void* dataBytes = _data.bytes;
238 | NSUInteger dataLength = range.location - 2;
239 | if (_subParser) {
240 | if (![_subParser appendBytes:dataBytes length:(dataLength + 2)] || ![_subParser isAtEnd]) {
241 | GWS_DNOT_REACHED();
242 | success = NO;
243 | }
244 | _subParser = nil;
245 | } else if (_tmpPath) {
246 | ssize_t result = write(_tmpFile, dataBytes, dataLength);
247 | if (result == (ssize_t)dataLength) {
248 | if (close(_tmpFile) == 0) {
249 | _tmpFile = 0;
250 | GCDWebServerMultiPartFile* file = [[GCDWebServerMultiPartFile alloc] initWithControlName:_controlName contentType:_contentType fileName:_fileName temporaryPath:_tmpPath];
251 | [_files addObject:file];
252 | } else {
253 | GWS_DNOT_REACHED();
254 | success = NO;
255 | }
256 | } else {
257 | GWS_DNOT_REACHED();
258 | success = NO;
259 | }
260 | _tmpPath = nil;
261 | } else {
262 | NSData* data = [[NSData alloc] initWithBytes:(void*)dataBytes length:dataLength];
263 | GCDWebServerMultiPartArgument* argument = [[GCDWebServerMultiPartArgument alloc] initWithControlName:_controlName contentType:_contentType data:data];
264 | [_arguments addObject:argument];
265 | }
266 | }
267 |
268 | if (subRange1.location != NSNotFound) {
269 | [_data replaceBytesInRange:NSMakeRange(0, subRange1.location + subRange1.length) withBytes:NULL length:0];
270 | _state = kParserState_Headers;
271 | success = [self _parseData];
272 | } else {
273 | _state = kParserState_End;
274 | }
275 | }
276 | } else {
277 | NSUInteger margin = 2 * _boundary.length;
278 | if (_data.length > margin) {
279 | NSUInteger length = _data.length - margin;
280 | if (_subParser) {
281 | if ([_subParser appendBytes:_data.bytes length:length]) {
282 | [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
283 | } else {
284 | GWS_DNOT_REACHED();
285 | success = NO;
286 | }
287 | } else if (_tmpPath) {
288 | ssize_t result = write(_tmpFile, _data.bytes, length);
289 | if (result == (ssize_t)length) {
290 | [_data replaceBytesInRange:NSMakeRange(0, length) withBytes:NULL length:0];
291 | } else {
292 | GWS_DNOT_REACHED();
293 | success = NO;
294 | }
295 | }
296 | }
297 | }
298 | }
299 |
300 | return success;
301 | }
302 |
303 | - (BOOL)appendBytes:(const void*)bytes length:(NSUInteger)length {
304 | [_data appendBytes:bytes length:length];
305 | return [self _parseData];
306 | }
307 |
308 | - (BOOL)isAtEnd {
309 | return (_state == kParserState_End);
310 | }
311 |
312 | @end
313 |
314 | @interface GCDWebServerMultiPartFormRequest ()
315 | @property(nonatomic) NSMutableArray* arguments;
316 | @property(nonatomic) NSMutableArray* files;
317 | @end
318 |
319 | @implementation GCDWebServerMultiPartFormRequest {
320 | GCDWebServerMIMEStreamParser* _parser;
321 | }
322 |
323 | + (NSString*)mimeType {
324 | return @"multipart/form-data";
325 | }
326 |
327 | - (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query {
328 | if ((self = [super initWithMethod:method url:url headers:headers path:path query:query])) {
329 | _arguments = [[NSMutableArray alloc] init];
330 | _files = [[NSMutableArray alloc] init];
331 | }
332 | return self;
333 | }
334 |
335 | - (BOOL)open:(NSError**)error {
336 | NSString* boundary = GCDWebServerExtractHeaderValueParameter(self.contentType, @"boundary");
337 | _parser = [[GCDWebServerMIMEStreamParser alloc] initWithBoundary:boundary defaultControlName:nil arguments:_arguments files:_files];
338 | if (_parser == nil) {
339 | if (error) {
340 | *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Failed starting to parse multipart form data"}];
341 | }
342 | return NO;
343 | }
344 | return YES;
345 | }
346 |
347 | - (BOOL)writeData:(NSData*)data error:(NSError**)error {
348 | if (![_parser appendBytes:data.bytes length:data.length]) {
349 | if (error) {
350 | *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Failed continuing to parse multipart form data"}];
351 | }
352 | return NO;
353 | }
354 | return YES;
355 | }
356 |
357 | - (BOOL)close:(NSError**)error {
358 | BOOL atEnd = [_parser isAtEnd];
359 | _parser = nil;
360 | if (!atEnd) {
361 | if (error) {
362 | *error = [NSError errorWithDomain:kGCDWebServerErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Failed finishing to parse multipart form data"}];
363 | }
364 | return NO;
365 | }
366 | return YES;
367 | }
368 |
369 | - (GCDWebServerMultiPartArgument*)firstArgumentForControlName:(NSString*)name {
370 | for (GCDWebServerMultiPartArgument* argument in _arguments) {
371 | if ([argument.controlName isEqualToString:name]) {
372 | return argument;
373 | }
374 | }
375 | return nil;
376 | }
377 |
378 | - (GCDWebServerMultiPartFile*)firstFileForControlName:(NSString*)name {
379 | for (GCDWebServerMultiPartFile* file in _files) {
380 | if ([file.controlName isEqualToString:name]) {
381 | return file;
382 | }
383 | }
384 | return nil;
385 | }
386 |
387 | - (NSString*)description {
388 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
389 | if (_arguments.count) {
390 | [description appendString:@"\n"];
391 | for (GCDWebServerMultiPartArgument* argument in _arguments) {
392 | [description appendFormat:@"\n%@ (%@)\n", argument.controlName, argument.contentType];
393 | [description appendString:GCDWebServerDescribeData(argument.data, argument.contentType)];
394 | }
395 | }
396 | if (_files.count) {
397 | [description appendString:@"\n"];
398 | for (GCDWebServerMultiPartFile* file in _files) {
399 | [description appendFormat:@"\n%@ (%@): %@\n{%@}", file.controlName, file.contentType, file.fileName, file.temporaryPath];
400 | }
401 | }
402 | return description;
403 | }
404 |
405 | @end
406 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServerDataRequest.h"
29 |
30 | NS_ASSUME_NONNULL_BEGIN
31 |
32 | /**
33 | * The GCDWebServerURLEncodedFormRequest subclass of GCDWebServerRequest
34 | * parses the body of the HTTP request as a URL encoded form using
35 | * GCDWebServerParseURLEncodedForm().
36 | */
37 | @interface GCDWebServerURLEncodedFormRequest : GCDWebServerDataRequest
38 |
39 | /**
40 | * Returns the unescaped control names and values for the URL encoded form.
41 | *
42 | * The text encoding used to interpret the data is extracted from the
43 | * "Content-Type" header or defaults to UTF-8.
44 | */
45 | @property(nonatomic, readonly) NSDictionary* arguments;
46 |
47 | /**
48 | * Returns the MIME type for URL encoded forms
49 | * i.e. "application/x-www-form-urlencoded".
50 | */
51 | + (NSString*)mimeType;
52 |
53 | @end
54 |
55 | NS_ASSUME_NONNULL_END
56 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 GCDWebServerURLEncodedFormRequest
35 |
36 | + (NSString*)mimeType {
37 | return @"application/x-www-form-urlencoded";
38 | }
39 |
40 | - (BOOL)close:(NSError**)error {
41 | if (![super close:error]) {
42 | return NO;
43 | }
44 |
45 | NSString* charset = GCDWebServerExtractHeaderValueParameter(self.contentType, @"charset");
46 | NSString* string = [[NSString alloc] initWithData:self.data encoding:GCDWebServerStringEncodingFromCharset(charset)];
47 | _arguments = GCDWebServerParseURLEncodedForm(string);
48 | return YES;
49 | }
50 |
51 | - (NSString*)description {
52 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
53 | [description appendString:@"\n"];
54 | for (NSString* argument in [[_arguments allKeys] sortedArrayUsingSelector:@selector(compare:)]) {
55 | [description appendFormat:@"\n%@ = %@", argument, [_arguments objectForKey:argument]];
56 | }
57 | return description;
58 | }
59 |
60 | @end
61 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 GCDWebServerDataResponse subclass of GCDWebServerResponse reads the body
34 | * of the HTTP response from memory.
35 | */
36 | @interface GCDWebServerDataResponse : GCDWebServerResponse
37 | @property(nonatomic, copy) NSString* contentType; // Redeclare as non-null
38 |
39 | /**
40 | * Creates a response with data in memory and a given content type.
41 | */
42 | + (instancetype)responseWithData:(NSData*)data contentType:(NSString*)type;
43 |
44 | /**
45 | * This method is the designated initializer for the class.
46 | */
47 | - (instancetype)initWithData:(NSData*)data contentType:(NSString*)type;
48 |
49 | @end
50 |
51 | @interface GCDWebServerDataResponse (Extensions)
52 |
53 | /**
54 | * Creates a data response from text encoded using UTF-8.
55 | */
56 | + (nullable instancetype)responseWithText:(NSString*)text;
57 |
58 | /**
59 | * Creates a data response from HTML encoded using UTF-8.
60 | */
61 | + (nullable instancetype)responseWithHTML:(NSString*)html;
62 |
63 | /**
64 | * Creates a data response from an HTML template encoded using UTF-8.
65 | * See -initWithHTMLTemplate:variables: for details.
66 | */
67 | + (nullable instancetype)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables;
68 |
69 | /**
70 | * Creates a data response from a serialized JSON object and the default
71 | * "application/json" content type.
72 | */
73 | + (nullable instancetype)responseWithJSONObject:(id)object;
74 |
75 | /**
76 | * Creates a data response from a serialized JSON object and a custom
77 | * content type.
78 | */
79 | + (nullable instancetype)responseWithJSONObject:(id)object contentType:(NSString*)type;
80 |
81 | /**
82 | * Initializes a data response from text encoded using UTF-8.
83 | */
84 | - (nullable instancetype)initWithText:(NSString*)text;
85 |
86 | /**
87 | * Initializes a data response from HTML encoded using UTF-8.
88 | */
89 | - (nullable instancetype)initWithHTML:(NSString*)html;
90 |
91 | /**
92 | * Initializes a data response from an HTML template encoded using UTF-8.
93 | *
94 | * All occurences of "%variable%" within the HTML template are replaced with
95 | * their corresponding values.
96 | */
97 | - (nullable instancetype)initWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables;
98 |
99 | /**
100 | * Initializes a data response from a serialized JSON object and the default
101 | * "application/json" content type.
102 | */
103 | - (nullable instancetype)initWithJSONObject:(id)object;
104 |
105 | /**
106 | * Initializes a data response from a serialized JSON object and a custom
107 | * content type.
108 | */
109 | - (nullable instancetype)initWithJSONObject:(id)object contentType:(NSString*)type;
110 |
111 | @end
112 |
113 | NS_ASSUME_NONNULL_END
114 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 GCDWebServerDataResponse {
35 | NSData* _data;
36 | BOOL _done;
37 | }
38 |
39 | @dynamic contentType;
40 |
41 | + (instancetype)responseWithData:(NSData*)data contentType:(NSString*)type {
42 | return [(GCDWebServerDataResponse*)[[self class] alloc] initWithData:data contentType:type];
43 | }
44 |
45 | - (instancetype)initWithData:(NSData*)data contentType:(NSString*)type {
46 | if ((self = [super init])) {
47 | _data = data;
48 |
49 | self.contentType = type;
50 | self.contentLength = data.length;
51 | }
52 | return self;
53 | }
54 |
55 | - (NSData*)readData:(NSError**)error {
56 | NSData* data;
57 | if (_done) {
58 | data = [NSData data];
59 | } else {
60 | data = _data;
61 | _done = YES;
62 | }
63 | return data;
64 | }
65 |
66 | - (NSString*)description {
67 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
68 | [description appendString:@"\n\n"];
69 | [description appendString:GCDWebServerDescribeData(_data, self.contentType)];
70 | return description;
71 | }
72 |
73 | @end
74 |
75 | @implementation GCDWebServerDataResponse (Extensions)
76 |
77 | + (instancetype)responseWithText:(NSString*)text {
78 | return [(GCDWebServerDataResponse*)[self alloc] initWithText:text];
79 | }
80 |
81 | + (instancetype)responseWithHTML:(NSString*)html {
82 | return [(GCDWebServerDataResponse*)[self alloc] initWithHTML:html];
83 | }
84 |
85 | + (instancetype)responseWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
86 | return [(GCDWebServerDataResponse*)[self alloc] initWithHTMLTemplate:path variables:variables];
87 | }
88 |
89 | + (instancetype)responseWithJSONObject:(id)object {
90 | return [(GCDWebServerDataResponse*)[self alloc] initWithJSONObject:object];
91 | }
92 |
93 | + (instancetype)responseWithJSONObject:(id)object contentType:(NSString*)type {
94 | return [(GCDWebServerDataResponse*)[self alloc] initWithJSONObject:object contentType:type];
95 | }
96 |
97 | - (instancetype)initWithText:(NSString*)text {
98 | NSData* data = [text dataUsingEncoding:NSUTF8StringEncoding];
99 | if (data == nil) {
100 | GWS_DNOT_REACHED();
101 | return nil;
102 | }
103 | return [self initWithData:data contentType:@"text/plain; charset=utf-8"];
104 | }
105 |
106 | - (instancetype)initWithHTML:(NSString*)html {
107 | NSData* data = [html dataUsingEncoding:NSUTF8StringEncoding];
108 | if (data == nil) {
109 | GWS_DNOT_REACHED();
110 | return nil;
111 | }
112 | return [self initWithData:data contentType:@"text/html; charset=utf-8"];
113 | }
114 |
115 | - (instancetype)initWithHTMLTemplate:(NSString*)path variables:(NSDictionary*)variables {
116 | NSMutableString* html = [[NSMutableString alloc] initWithContentsOfFile:path encoding:NSUTF8StringEncoding error:NULL];
117 | [variables enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSString* value, BOOL* stop) {
118 | [html replaceOccurrencesOfString:[NSString stringWithFormat:@"%%%@%%", key] withString:value options:0 range:NSMakeRange(0, html.length)];
119 | }];
120 | return [self initWithHTML:html];
121 | }
122 |
123 | - (instancetype)initWithJSONObject:(id)object {
124 | return [self initWithJSONObject:object contentType:@"application/json"];
125 | }
126 |
127 | - (instancetype)initWithJSONObject:(id)object contentType:(NSString*)type {
128 | NSData* data = [NSJSONSerialization dataWithJSONObject:object options:0 error:NULL];
129 | if (data == nil) {
130 | GWS_DNOT_REACHED();
131 | return nil;
132 | }
133 | return [self initWithData:data contentType:type];
134 | }
135 |
136 | @end
137 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 "GCDWebServerDataResponse.h"
29 | #import "GCDWebServerHTTPStatusCodes.h"
30 |
31 | NS_ASSUME_NONNULL_BEGIN
32 |
33 | /**
34 | * The GCDWebServerDataResponse subclass of GCDWebServerDataResponse generates
35 | * an HTML body from an HTTP status code and an error message.
36 | */
37 | @interface GCDWebServerErrorResponse : GCDWebServerDataResponse
38 |
39 | /**
40 | * Creates a client error response with the corresponding HTTP status code.
41 | */
42 | + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3);
43 |
44 | /**
45 | * Creates a server error response with the corresponding HTTP status code.
46 | */
47 | + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3);
48 |
49 | /**
50 | * Creates a client error response with the corresponding HTTP status code
51 | * and an underlying NSError.
52 | */
53 | + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(nullable NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4);
54 |
55 | /**
56 | * Creates a server error response with the corresponding HTTP status code
57 | * and an underlying NSError.
58 | */
59 | + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(nullable NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4);
60 |
61 | /**
62 | * Initializes a client error response with the corresponding HTTP status code.
63 | */
64 | - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3);
65 |
66 | /**
67 | * Initializes a server error response with the corresponding HTTP status code.
68 | */
69 | - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... NS_FORMAT_FUNCTION(2, 3);
70 |
71 | /**
72 | * Initializes a client error response with the corresponding HTTP status code
73 | * and an underlying NSError.
74 | */
75 | - (instancetype)initWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(nullable NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4);
76 |
77 | /**
78 | * Initializes a server error response with the corresponding HTTP status code
79 | * and an underlying NSError.
80 | */
81 | - (instancetype)initWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(nullable NSError*)underlyingError message:(NSString*)format, ... NS_FORMAT_FUNCTION(3, 4);
82 |
83 | @end
84 |
85 | NS_ASSUME_NONNULL_END
86 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 GCDWebServerErrorResponse
35 |
36 | + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
37 | GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
38 | va_list arguments;
39 | va_start(arguments, format);
40 | GCDWebServerErrorResponse* response = [(GCDWebServerErrorResponse*)[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
41 | va_end(arguments);
42 | return response;
43 | }
44 |
45 | + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode message:(NSString*)format, ... {
46 | GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
47 | va_list arguments;
48 | va_start(arguments, format);
49 | GCDWebServerErrorResponse* response = [(GCDWebServerErrorResponse*)[self alloc] initWithStatusCode:errorCode underlyingError:nil messageFormat:format arguments:arguments];
50 | va_end(arguments);
51 | return response;
52 | }
53 |
54 | + (instancetype)responseWithClientError:(GCDWebServerClientErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
55 | GWS_DCHECK(((NSInteger)errorCode >= 400) && ((NSInteger)errorCode < 500));
56 | va_list arguments;
57 | va_start(arguments, format);
58 | GCDWebServerErrorResponse* response = [(GCDWebServerErrorResponse*)[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
59 | va_end(arguments);
60 | return response;
61 | }
62 |
63 | + (instancetype)responseWithServerError:(GCDWebServerServerErrorHTTPStatusCode)errorCode underlyingError:(NSError*)underlyingError message:(NSString*)format, ... {
64 | GWS_DCHECK(((NSInteger)errorCode >= 500) && ((NSInteger)errorCode < 600));
65 | va_list arguments;
66 | va_start(arguments, format);
67 | GCDWebServerErrorResponse* response = [(GCDWebServerErrorResponse*)[self alloc] initWithStatusCode:errorCode underlyingError:underlyingError messageFormat:format arguments:arguments];
68 | va_end(arguments);
69 | return response;
70 | }
71 |
72 | static inline NSString* _EscapeHTMLString(NSString* string) {
73 | return [string stringByReplacingOccurrencesOfString:@"\"" withString:@"""];
74 | }
75 |
76 | - (instancetype)initWithStatusCode:(NSInteger)statusCode underlyingError:(NSError*)underlyingError messageFormat:(NSString*)format arguments:(va_list)arguments {
77 | NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
78 | NSString* title = [NSString stringWithFormat:@"HTTP Error %i", (int)statusCode];
79 | NSString* error = underlyingError ? [NSString stringWithFormat:@"[%@] %@ (%li)", underlyingError.domain, _EscapeHTMLString(underlyingError.localizedDescription), (long)underlyingError.code] : @"";
80 | NSString* html = [NSString stringWithFormat:@"%@%@: %@
%@
",
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 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 [(GCDWebServerFileResponse*)[[self class] alloc] initWithFile:path];
49 | }
50 |
51 | + (instancetype)responseWithFile:(NSString*)path isAttachment:(BOOL)attachment {
52 | return [(GCDWebServerFileResponse*)[[self class] alloc] initWithFile:path isAttachment:attachment];
53 | }
54 |
55 | + (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range {
56 | return [(GCDWebServerFileResponse*)[[self class] alloc] initWithFile:path byteRange:range];
57 | }
58 |
59 | + (instancetype)responseWithFile:(NSString*)path byteRange:(NSRange)range isAttachment:(BOOL)attachment {
60 | return [(GCDWebServerFileResponse*)[[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 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.m:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2012-2019, 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 [(GCDWebServerStreamedResponse*)[[self class] alloc] initWithContentType:type streamBlock:block];
42 | }
43 |
44 | + (instancetype)responseWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
45 | return [(GCDWebServerStreamedResponse*)[[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 | NSError* error = nil;
52 | NSData* data = block(&error);
53 | completionBlock(data, error);
54 | }];
55 | }
56 |
57 | - (instancetype)initWithContentType:(NSString*)type asyncStreamBlock:(GCDWebServerAsyncStreamBlock)block {
58 | if ((self = [super init])) {
59 | _block = [block copy];
60 |
61 | self.contentType = type;
62 | }
63 | return self;
64 | }
65 |
66 | - (void)asyncReadDataWithCompletion:(GCDWebServerBodyReaderCompletionBlock)block {
67 | _block(block);
68 | }
69 |
70 | - (NSString*)description {
71 | NSMutableString* description = [NSMutableString stringWithString:[super description]];
72 | [description appendString:@"\n\n"];
73 | return description;
74 | }
75 |
76 | @end
77 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/GCDWebServer/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012-2014, Pierre-Olivier Latour
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 | * Redistributions of source code must retain the above copyright
7 | notice, this list of conditions and the following disclaimer.
8 | * Redistributions in binary form must reproduce the above copyright
9 | notice, this list of conditions and the following disclaimer in the
10 | documentation and/or other materials provided with the distribution.
11 | * The name of Pierre-Olivier Latour may not be used to endorse
12 | or promote products derived from this software without specific
13 | prior written permission.
14 |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServer.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServer.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerConnection.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerDataRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerDataResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerErrorResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerFileRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerFileResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerFunctions.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerHTTPStatusCodes.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerMultiPartFormRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerPrivate.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerPrivate.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerStreamedResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Private/GCDWebServer/GCDWebServerURLEncodedFormRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServer.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServer.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerConnection.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerConnection.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerDataRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerDataRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerDataResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerDataResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerErrorResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerErrorResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerFileRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerFileRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerFileResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerFileResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerFunctions.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerFunctions.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerHTTPStatusCodes.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerMultiPartFormRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Core/GCDWebServerResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerStreamedResponse.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Responses/GCDWebServerStreamedResponse.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Headers/Public/GCDWebServer/GCDWebServerURLEncodedFormRequest.h:
--------------------------------------------------------------------------------
1 | ../../../GCDWebServer/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h
--------------------------------------------------------------------------------
/hopper_helper/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - GCDWebServer (3.5.4):
3 | - GCDWebServer/Core (= 3.5.4)
4 | - GCDWebServer/Core (3.5.4)
5 |
6 | DEPENDENCIES:
7 | - GCDWebServer (~> 3.0)
8 |
9 | SPEC REPOS:
10 | trunk:
11 | - GCDWebServer
12 |
13 | SPEC CHECKSUMS:
14 | GCDWebServer: 2c156a56c8226e2d5c0c3f208a3621ccffbe3ce4
15 |
16 | PODFILE CHECKSUM: 278b91d4fba272f8f3d2e61a0855a98125a6b524
17 |
18 | COCOAPODS: 1.10.1
19 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Pods.xcodeproj/xcuserdata/ethanarbuckle.xcuserdatad/xcschemes/GCDWebServer.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Pods.xcodeproj/xcuserdata/ethanarbuckle.xcuserdatad/xcschemes/Pods-hopper_helper.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Pods.xcodeproj/xcuserdata/ethanarbuckle.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | GCDWebServer.xcscheme
8 |
9 | isShown
10 |
11 | orderHint
12 | 0
13 |
14 | Pods-hopper_helper.xcscheme
15 |
16 | isShown
17 |
18 | orderHint
19 | 1
20 |
21 |
22 | SuppressBuildableAutocreation
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/GCDWebServer/GCDWebServer-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_GCDWebServer : NSObject
3 | @end
4 | @implementation PodsDummy_GCDWebServer
5 | @end
6 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/GCDWebServer/GCDWebServer-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #else
4 | #ifndef FOUNDATION_EXPORT
5 | #if defined(__cplusplus)
6 | #define FOUNDATION_EXPORT extern "C"
7 | #else
8 | #define FOUNDATION_EXPORT extern
9 | #endif
10 | #endif
11 | #endif
12 |
13 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/GCDWebServer/GCDWebServer.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GCDWebServer
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GCDWebServer" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GCDWebServer"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/GCDWebServer
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/GCDWebServer/GCDWebServer.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GCDWebServer
3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/GCDWebServer" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GCDWebServer"
5 | PODS_BUILD_DIR = ${BUILD_DIR}
6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
7 | PODS_ROOT = ${SRCROOT}
8 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/GCDWebServer
9 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
10 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
11 | SKIP_INSTALL = YES
12 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
13 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/Pods-hopper_helper/Pods-hopper_helper-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## GCDWebServer
5 |
6 | Copyright (c) 2012-2014, Pierre-Olivier Latour
7 | All rights reserved.
8 |
9 | Redistribution and use in source and binary forms, with or without
10 | modification, are permitted provided that the following conditions are met:
11 | * Redistributions of source code must retain the above copyright
12 | notice, this list of conditions and the following disclaimer.
13 | * Redistributions in binary form must reproduce the above copyright
14 | notice, this list of conditions and the following disclaimer in the
15 | documentation and/or other materials provided with the distribution.
16 | * The name of Pierre-Olivier Latour may not be used to endorse
17 | or promote products derived from this software without specific
18 | prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
24 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | Generated by CocoaPods - https://cocoapods.org
32 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/Pods-hopper_helper/Pods-hopper_helper-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2012-2014, Pierre-Olivier Latour
18 | All rights reserved.
19 |
20 | Redistribution and use in source and binary forms, with or without
21 | modification, are permitted provided that the following conditions are met:
22 | * Redistributions of source code must retain the above copyright
23 | notice, this list of conditions and the following disclaimer.
24 | * Redistributions in binary form must reproduce the above copyright
25 | notice, this list of conditions and the following disclaimer in the
26 | documentation and/or other materials provided with the distribution.
27 | * The name of Pierre-Olivier Latour may not be used to endorse
28 | or promote products derived from this software without specific
29 | prior written permission.
30 |
31 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
32 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
33 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
34 | DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
35 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
40 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 |
42 | License
43 | BSD
44 | Title
45 | GCDWebServer
46 | Type
47 | PSGroupSpecifier
48 |
49 |
50 | FooterText
51 | Generated by CocoaPods - https://cocoapods.org
52 | Title
53 |
54 | Type
55 | PSGroupSpecifier
56 |
57 |
58 | StringsTable
59 | Acknowledgements
60 | Title
61 | Acknowledgements
62 |
63 |
64 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/Pods-hopper_helper/Pods-hopper_helper-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_hopper_helper : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_hopper_helper
5 | @end
6 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/Pods-hopper_helper/Pods-hopper_helper.debug.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GCDWebServer"
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GCDWebServer"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"GCDWebServer" -l"z" -framework "SystemConfiguration"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/hopper_helper/Pods/Target Support Files/Pods-hopper_helper/Pods-hopper_helper.release.xcconfig:
--------------------------------------------------------------------------------
1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/GCDWebServer"
4 | LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GCDWebServer"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"GCDWebServer" -l"z" -framework "SystemConfiguration"
6 | PODS_BUILD_DIR = ${BUILD_DIR}
7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
9 | PODS_ROOT = ${SRCROOT}/Pods
10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates
11 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES
12 |
--------------------------------------------------------------------------------
/hopper_helper/README.md:
--------------------------------------------------------------------------------
1 | Move the produced .hopperCPU bundle to `~/Library/Application Support/Hopper/PlugIns/v4/CPUs/HopperTweakStudio.hopperCPU`. You can make it a symlink to this project's build output for debugging convenience
--------------------------------------------------------------------------------
/hopper_helper/hopper_helper.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/hopper_helper/plugin/handlers.h:
--------------------------------------------------------------------------------
1 | //
2 | // handlers.h
3 | // hopper_helper
4 | //
5 | // Created by Ethan Arbuckle on 4/12/21.
6 | //
7 |
8 | #ifndef handlers_h
9 | #define handlers_h
10 |
11 | #import "GCDWebServerDataResponse.h"
12 |
13 | #define objcInvokeT(a, b, t) ((t (*)(id, SEL))objc_msgSend)(a, NSSelectorFromString(b))
14 | #define objcInvoke(a, b) objcInvokeT(a, b, id)
15 | #define objcInvoke_1(a, b, c) ((id (*)(id, SEL, typeof(c)))objc_msgSend)(a, NSSelectorFromString(b), c)
16 |
17 |
18 | typedef id (^HandlerBlock)(NSDictionary *, id, id);
19 |
20 | extern HandlerBlock StringsHandler;
21 | extern HandlerBlock SegmentsHandler;
22 | extern HandlerBlock ProceduresHandler;
23 | extern HandlerBlock DecompileHandler;
24 | extern HandlerBlock DisassembleHandler;
25 | extern HandlerBlock FilePathHandler;
26 | extern HandlerBlock TerminateHandler;
27 | extern HandlerBlock ProcedureSignatureHandler;
28 | extern HandlerBlock StatusHandler;
29 | extern HandlerBlock XrefsHandler;
30 | extern HandlerBlock LogMessagesHandler;
31 | extern HandlerBlock AllPseudoCodeHandler;
32 |
33 | #endif /* handlers_h */
34 |
--------------------------------------------------------------------------------
/hopper_helper/plugin/handlers.m:
--------------------------------------------------------------------------------
1 | //
2 | // handlers.m
3 | // pluginBackend
4 | //
5 | // Created by Ethan Arbuckle on 4/12/21.
6 | //
7 |
8 | #import
9 | #import "handlers.h"
10 | #include
11 |
12 |
13 | // List all strings in a document
14 | HandlerBlock StringsHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
15 |
16 | if (!disassembledFile) {
17 | return nil;
18 | }
19 |
20 | return objcInvoke(disassembledFile, @"allStrings");
21 | };
22 |
23 |
24 | // List all segments in a document
25 | HandlerBlock SegmentsHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
26 |
27 | if (!disassembledFile) {
28 | return nil;
29 | }
30 |
31 | NSArray *segments = objcInvoke(disassembledFile, @"segments");
32 |
33 | NSMutableArray *segmentNames = [[NSMutableArray alloc] init];
34 | for (id segment in segments) {
35 | NSString *segmentName = objcInvoke(segment, @"segmentName");
36 | [segmentNames addObject:segmentName];
37 | }
38 |
39 | return segmentNames;
40 | };
41 |
42 |
43 | // List all procedures in a document
44 | HandlerBlock ProceduresHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
45 |
46 | if (!disassembledFile) {
47 | return nil;
48 | }
49 |
50 | NSArray *allNamedAddresses = objcInvoke(disassembledFile, @"allNamedAddresses");
51 |
52 | NSMutableArray *response = [[NSMutableArray alloc] init];
53 | for (id address in allNamedAddresses) {
54 |
55 | NSString *demangledName = objcInvoke_1(disassembledFile, @"demangledNameForVirtualAddress:", [address longLongValue]);
56 | NSDictionary *namedEntry = @{
57 | @"address": @([address unsignedLongLongValue]),
58 | @"label": demangledName,
59 | };
60 | [response addObject:namedEntry];
61 | }
62 |
63 | return response;
64 | };
65 |
66 |
67 | // Get pseudocode text for a specified function start address
68 | HandlerBlock DecompileHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
69 |
70 | NSString *procedureAddress = requestData[@"procedure_address"];
71 | if (!disassembledFile || !procedureAddress) {
72 | return nil;
73 | }
74 |
75 | id procedure = objcInvoke_1(disassembledFile, @"procedureAt:", [procedureAddress longLongValue]);
76 | if (!procedure) {
77 | return nil;
78 | }
79 |
80 | id pseudoCode = objcInvoke(procedure, @"completePseudoCode");
81 | NSString *pseudoCodeString = objcInvoke(pseudoCode, @"string");
82 |
83 | return pseudoCodeString;
84 | };
85 |
86 |
87 | // Get assembly text for a specified function start address
88 | HandlerBlock DisassembleHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
89 |
90 | NSString *procedureAddress = requestData[@"procedure_address"];
91 | if (!disassembledFile || !procedureAddress) {
92 | return nil;
93 | }
94 |
95 | id procedure = objcInvoke_1(disassembledFile, @"procedureAt:", [procedureAddress longLongValue]);
96 | if (!procedure) {
97 | return nil;
98 | }
99 | NSArray *basicBlocks = objcInvoke(procedure, @"basicBlocks");
100 | id containingSegment = objcInvoke_1(disassembledFile, @"segmentForVirtualAddress:", [procedureAddress longLongValue]);
101 |
102 | NSMutableString *procedureAssemblyText = [[NSMutableString alloc] init];
103 | for (id basicBlock in basicBlocks) {
104 |
105 | uint64_t instrCursor = objcInvokeT(basicBlock, @"from", uint64_t);
106 | uint64_t basicBlockEndAddress = objcInvokeT(basicBlock, @"to", uint64_t);
107 | while (instrCursor <= basicBlockEndAddress) {
108 |
109 | NSArray *asmLines = ((id (*)(id, SEL, uint64_t, BOOL, BOOL, BOOL, BOOL, BOOL))objc_msgSend)(containingSegment, NSSelectorFromString(@"stringsForVirtualAddress:includingDecorations:inlineComments:addressField:hexColumn:compactMode:"), instrCursor, YES, YES, YES, NO, NO);
110 |
111 | for (id asmLine in asmLines) {
112 | NSString *assemblyLineText = objcInvoke(asmLine, @"string");
113 | [procedureAssemblyText appendString:assemblyLineText];
114 | [procedureAssemblyText appendString:@"\n"];
115 | }
116 |
117 | instrCursor += ((uint64_t (*)(id, SEL, uint64_t))objc_msgSend)(containingSegment, NSSelectorFromString(@"getByteLengthAtVirtualAddress:"), instrCursor);
118 | }
119 | }
120 |
121 | return procedureAssemblyText;
122 | };
123 |
124 |
125 | // Get the executable path for a document
126 | HandlerBlock FilePathHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
127 |
128 | if (!disassembledFile) {
129 | return nil;
130 | }
131 |
132 | return objcInvoke(disassembledFile, @"originalFilePath");
133 | };
134 |
135 |
136 | // Terminate Hopper (all documents)
137 | HandlerBlock TerminateHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
138 |
139 | exit(0);
140 | return nil;
141 | };
142 |
143 |
144 | // Get the prettified function signature for a specified function start address
145 | HandlerBlock ProcedureSignatureHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
146 |
147 | NSString *procedureAddress = requestData[@"procedure_address"];
148 | if (!disassembledFile || !procedureAddress) {
149 | return nil;
150 | }
151 |
152 | id procedure = objcInvoke_1(disassembledFile, @"procedureAt:", [procedureAddress longLongValue]);
153 | if (!procedure) {
154 | return nil;
155 | }
156 |
157 | id signaturePseudoCode = objcInvoke(procedure, @"signaturePseudoCode");
158 | return objcInvoke(signaturePseudoCode, @"string");
159 | };
160 |
161 |
162 | // Query status of a Document's analysis
163 | HandlerBlock StatusHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
164 |
165 | if (!disassembledFile) {
166 | return nil;
167 | }
168 |
169 | BOOL activeAnalysis = objcInvokeT(disassembledFile, @"analysisInProgress", BOOL);
170 | return @{@"analysis_active": @(activeAnalysis)};
171 | };
172 |
173 |
174 | // List cross-references to a specified address
175 | HandlerBlock XrefsHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
176 |
177 | NSString *procedureAddress = requestData[@"procedure_address"];
178 | if (!disassembledFile || !procedureAddress) {
179 | return nil;
180 | }
181 |
182 | uint64_t address = [procedureAddress longLongValue];
183 | id containingSegment = objcInvoke_1(disassembledFile, @"segmentForVirtualAddress:", address);
184 | id xrefAsmLine = objcInvoke_1(containingSegment, @"formatXREFStringForAddress:", address);
185 | return objcInvoke(xrefAsmLine, @"string");
186 | };
187 |
188 |
189 | // Get all the log messages in the Log view for a document
190 | HandlerBlock LogMessagesHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
191 |
192 | if (!disassembledFile) {
193 | return nil;
194 | }
195 |
196 | id logView = objcInvoke(hopperDocument, @"logView");
197 | return objcInvoke(logView, @"string");
198 | };
199 |
200 |
201 | // Produce pseudocode for all procedures in a document
202 | HandlerBlock AllPseudoCodeHandler = ^id(NSDictionary *requestData, id hopperDocument, id disassembledFile) {
203 |
204 | if (!disassembledFile) {
205 | return nil;
206 | }
207 |
208 | NSArray *allProcedures = objcInvoke(disassembledFile, @"allProcedures");
209 |
210 | dispatch_queue_t exportQueue = dispatch_queue_create("com.cryptic-apps.hopper.pseudo-code.export", DISPATCH_QUEUE_SERIAL);
211 | __block NSMutableString *allPseudoCode = [[NSMutableString alloc] init];
212 | dispatch_apply([allProcedures count], exportQueue, ^(size_t index) {
213 |
214 | id procedure = allProcedures[index];
215 | id pseudoCode = ((id (*)(id, SEL, void *, int))objc_msgSend)(procedure, NSSelectorFromString(@"completePseudoCodeWithCancelationBlock:andOptions:"), NULL, 7);
216 | NSString *pseudoCodeString = objcInvoke(pseudoCode, @"string");
217 | [allPseudoCode appendFormat:@"%@\n", pseudoCodeString];
218 | });
219 |
220 | return allPseudoCode;
221 | };
222 |
--------------------------------------------------------------------------------
/hopper_helper/plugin/hopper_backend.m:
--------------------------------------------------------------------------------
1 | //
2 | // hopper_helper.m
3 | // hopper_helper
4 | //
5 | // Created by Ethan Arbuckle on 4/6/21.
6 | //
7 |
8 | #import
9 | #import "GCDWebServerDataRequest.h"
10 | #import "GCDWebServer.h"
11 | #include
12 | #include
13 | #import "handlers.h"
14 |
15 |
16 | static NSDictionary *(^allDocuments)(void) = ^id() {
17 | NSMutableDictionary *docNamesAndDocs = [[NSMutableDictionary alloc] init];
18 |
19 | NSArray *allDocuments = objcInvoke(NSClassFromString(@"HopperAppDelegate"), @"allDocuments");
20 | for (id document in allDocuments) {
21 | NSString *documentName = objcInvoke(document, @"documentName");
22 | docNamesAndDocs[documentName] = document;
23 | }
24 | return docNamesAndDocs;
25 | };
26 |
27 | __attribute__((constructor)) void init(void) {
28 |
29 | NSLog(@"real TweakStudio plugin injected");
30 |
31 | // Create server
32 | GCDWebServer* webServer = [[GCDWebServer alloc] init];
33 | void (^addPostHandler)(NSString *path, HandlerBlock) = ^void(NSString *path, id (^handler)(NSDictionary *requestData, id hopperDocument, id disassembledFile)) {
34 |
35 | [webServer addHandlerForMethod:@"POST" path:path requestClass:[GCDWebServerDataRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerDataRequest * _Nonnull request) {
36 |
37 | NSDictionary *requestBody = [NSJSONSerialization JSONObjectWithData:request.data options:0 error:nil];
38 | NSString *requestedDocument = requestBody[@"document_name"];
39 |
40 | id hopperDocument = nil;
41 | id disassembledFile = nil;
42 | if (requestedDocument) {
43 |
44 | // Search for a document with the requested name
45 | NSDictionary *documents = allDocuments();
46 | for (NSString *documentName in documents) {
47 | if ([documentName isEqualToString:requestedDocument]) {
48 | hopperDocument = documents[documentName];
49 | break;
50 | }
51 | }
52 |
53 | disassembledFile = objcInvoke(hopperDocument, @"disassembledFile");
54 | }
55 |
56 | id handlerResponse = handler(requestBody, hopperDocument, disassembledFile);
57 | NSMutableDictionary *wrappedResponse = [[NSMutableDictionary alloc] init];
58 |
59 | wrappedResponse[@"data"] = handlerResponse;
60 | if (!handlerResponse) {
61 | // todo errors
62 | wrappedResponse[@"error"] = @"nondescript error";
63 | }
64 |
65 | return [GCDWebServerDataResponse responseWithJSONObject:wrappedResponse];
66 | }];
67 | };
68 |
69 | addPostHandler(@"/strings", StringsHandler);
70 | addPostHandler(@"/segments", SegmentsHandler);
71 | addPostHandler(@"/procedures", ProceduresHandler);
72 | addPostHandler(@"/decompile", DecompileHandler);
73 | addPostHandler(@"/disassemble", DisassembleHandler);
74 | addPostHandler(@"/filepath", FilePathHandler);
75 | addPostHandler(@"/terminate", TerminateHandler);
76 | addPostHandler(@"/procedure_signature", ProcedureSignatureHandler);
77 | addPostHandler(@"/status", StatusHandler);
78 | addPostHandler(@"/xrefs", XrefsHandler);
79 | addPostHandler(@"/logs", LogMessagesHandler);
80 | addPostHandler(@"/all_code", AllPseudoCodeHandler);
81 |
82 | [webServer addHandlerForMethod:@"GET" path:@"/documents" requestClass:[GCDWebServerRequest class] processBlock:^GCDWebServerResponse * _Nullable(__kindof GCDWebServerRequest * _Nonnull request) {
83 |
84 | NSArray *allDocumentNames = [allDocuments() allKeys];
85 | return [GCDWebServerDataResponse responseWithJSONObject:@{@"data": allDocumentNames}];
86 | }];
87 |
88 | int serverPort = 52349;
89 | if (![webServer startWithPort:serverPort bonjourName:nil]) {
90 |
91 | NSLog(@"Hopper already running on port: %d", serverPort);
92 | exit(0);
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/hopper_proxy.py:
--------------------------------------------------------------------------------
1 | #
2 | # hopper_proxy.py
3 | # IDA Objc
4 | #
5 | # Created by Ethan Arbuckle on 2021-03-05
6 | # Copyright (c) 2021 Ethan Arbuckle and Tanner Bennett. All rights reserved.
7 | #
8 |
9 | import json
10 | import subprocess
11 | import typing
12 | from abc import abstractmethod
13 | from http.server import BaseHTTPRequestHandler, HTTPServer
14 |
15 | if typing.TYPE_CHECKING:
16 | from hopper_api import Document
17 |
18 |
19 | class HopperHandler(object):
20 | @abstractmethod
21 | def run(cls):
22 | pass
23 |
24 | @classmethod
25 | def get_document_named(cls, document_name):
26 | for document in Document.getAllDocuments():
27 | if document.getDocumentName() == document_name:
28 | return document
29 | raise Exception("failed to find specified document")
30 |
31 |
32 | class TerminateHopper(HopperHandler):
33 | PATH = "/terminate"
34 |
35 | @classmethod
36 | def kill_hopper(cls):
37 | """Kill all running Hopper processes"""
38 | ps_output = subprocess.check_output(["ps", "aux"]).decode("utf-8")
39 | for ps_line in ps_output.splitlines():
40 | # Look for Hopper
41 | if "Hopper" in ps_line:
42 | components = ps_line.split(" ")
43 | # PID is the first number
44 | pid = [component for component in components if component.isnumeric()][0]
45 | # Terminate it
46 | subprocess.check_output(["kill", pid])
47 |
48 | @classmethod
49 | def run(cls):
50 | TerminateHopper.kill_hopper()
51 | pass
52 |
53 |
54 | class ListSegments(HopperHandler):
55 | PATH = "/segments"
56 |
57 | @classmethod
58 | def run(cls, document_name):
59 | document = cls.get_document_named(document_name)
60 | segments = document.getSegmentsList()
61 | return [segment.getName() for segment in segments]
62 |
63 |
64 | class ListProcedures(HopperHandler):
65 | PATH = "/procedures"
66 |
67 | @classmethod
68 | def run(cls, document_name):
69 | document = cls.get_document_named(document_name)
70 |
71 | named_procedures = []
72 | for segment_name in ListSegments.run():
73 | segment = document.getSegmentByName(segment_name)
74 | for label_address in segment.getNamedAddresses():
75 | named_procedures.append(
76 | {
77 | "label": segment.getDemangledNameAtAddress(label_address),
78 | "address": label_address,
79 | }
80 | )
81 |
82 | return named_procedures
83 |
84 |
85 | class ListStrings(HopperHandler):
86 | PATH = "/strings"
87 |
88 | @classmethod
89 | def run(cls, document_name):
90 | document = cls.get_document_named(document_name)
91 |
92 | cstrings_sect = document.getSectionByName("__cstring")
93 | text_seg = document.getSegmentByName("__TEXT")
94 | cstring_start = cstrings_sect.getStartingAddress()
95 |
96 | string_cursor = 0
97 | strings = []
98 | while string_cursor < cstrings_sect.getLength():
99 | stringlen = text_seg.getObjectLength(cstring_start + string_cursor)
100 | string = text_seg.readBytes(cstring_start + string_cursor, stringlen - 1).strip()
101 | string_cursor += max(stringlen, 1)
102 | strings.append(string)
103 | return strings
104 |
105 |
106 | class DecompileProcedure(HopperHandler):
107 | PATH = "/decompile"
108 |
109 | @classmethod
110 | def run(cls, document_name, procedure_address):
111 | if not procedure_address:
112 | raise Exception("did not specify procedure address")
113 |
114 | document = cls.get_document_named(document_name)
115 |
116 | # Hopper's API requires you to know the segment that contains a procedure (even though procs are
117 | # referenced by their absolute address in the binary).
118 | # Try all known segments
119 | for segment_name in ListSegments.run():
120 | segment = document.getSegmentByName(segment_name)
121 | procedure_candidate = segment.getProcedureAtAddress(procedure_address)
122 | if procedure_candidate:
123 | return procedure_candidate.decompile()
124 |
125 | raise Exception("Failed to find the specified procedure")
126 |
127 |
128 | class DisassembleProcedure(HopperHandler):
129 | PATH = "/disassemble"
130 |
131 | @classmethod
132 | def run(cls, document_name, procedure_address):
133 | document = cls.get_document_named(document_name)
134 | if not procedure_address:
135 | raise Exception("did not specify procedure address")
136 |
137 | disassembly = ""
138 |
139 | # Hopper's API requires you to know the segment that contains a procedure (even though procs are
140 | # referenced by their absolute address in the binary).
141 | # Try all known segments
142 | for segment_name in ListSegments.run():
143 | segment = document.getSegmentByName(segment_name)
144 | procedure_candidate = segment.getProcedureAtAddress(procedure_address)
145 | if procedure_candidate:
146 |
147 | for basic_block in procedure_candidate.basicBlockIterator():
148 | basic_block_start = basic_block.getStartingAddress()
149 | instr_cursor = basic_block_start
150 | while instr_cursor < basic_block.getEndingAddress():
151 | instr = segment.getInstructionAtAddress(instr_cursor)
152 | instr_args = [instr.getFormattedArgument(i) for i in xrange(instr.getArgumentCount())]
153 |
154 | instr_string = instr.getInstructionString() + " "
155 | instr_string += ", ".join(instr_args)
156 | instr_string += "\n"
157 | disassembly += instr_string
158 |
159 | instr_cursor += instr.getInstructionLength()
160 | # Maybe this should return a list of instructions, instead of combining them into 1 string?
161 | return disassembly
162 |
163 |
164 | class ListDocuments(HopperHandler):
165 | PATH = "/documents"
166 |
167 | @classmethod
168 | def run(cls):
169 |
170 | documents = []
171 | for document in Document.getAllDocuments():
172 | documents.append(document.getDocumentName())
173 |
174 | return documents
175 |
176 |
177 | class BackgroundProcessActive(HopperHandler):
178 | PATH = "/analysis"
179 |
180 | @classmethod
181 | def run(cls, document_name):
182 | document = cls.get_document_named(document_name)
183 | return {"active": document.backgroundProcessActive()}
184 |
185 |
186 | class DocumentFilePath(HopperHandler):
187 | PATH = "/filepath"
188 |
189 | @classmethod
190 | def run(cls, document_name):
191 | document = cls.get_document_named(document_name)
192 | return document.getExecutableFilePath()
193 |
194 |
195 | class RequestHandler(BaseHTTPRequestHandler):
196 | def do_POST(self):
197 | content_length = int(self.headers.get("Content-Length", 0))
198 | posted_data = json.loads(self.rfile.read(content_length)) if content_length > 0 else {}
199 |
200 | data_response = None
201 | error = None
202 |
203 | for handler in HopperHandler.__subclasses__():
204 | if self.path == handler.PATH:
205 |
206 | try:
207 | data_response = handler.run(**posted_data)
208 | json.dumps(data_response)
209 | self.send_response(200)
210 | except TypeError as e:
211 | self.send_response(500)
212 | error = str(e)
213 | except Exception as e:
214 | self.send_response(500)
215 | error = str(e)
216 |
217 | response = {"data": data_response}
218 | if error:
219 | response["error"] = error
220 |
221 | self.send_header("Content-type", "application/json")
222 | self.end_headers()
223 | self.wfile.write(json.dumps(response).encode("utf-8"))
224 |
225 |
226 | def start_server():
227 |
228 | httpd = HTTPServer(("", 52349), RequestHandler)
229 |
230 | try:
231 | httpd.serve_forever()
232 | except KeyboardInterrupt:
233 | pass
234 |
235 | httpd.server_close()
236 |
--------------------------------------------------------------------------------
/lzssdec:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EthanArbuckle/Hopper-Disassembler-API/c4740de2bda6a0826e9a94e9df93d7f8d5891557/lzssdec
--------------------------------------------------------------------------------
/patch_tcc_db.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import sqlite3
3 | from pathlib import Path
4 |
5 | tcc_db_path = Path("~/Library/Application Support/com.apple.TCC/TCC.db").expanduser()
6 | hopper_identifier = "com.cryptic-apps.hopper-web-4"
7 | vscode_identifier = "com.microsoft.VSCode"
8 |
9 | connection = sqlite3.connect(tcc_db_path.as_posix())
10 | cursor = connection.cursor()
11 |
12 | hopper_code_obj_identity = None
13 |
14 | cursor.execute("select * from access")
15 | for row in cursor.fetchall():
16 | entry_indirect_object_identifier = row[8]
17 | if entry_indirect_object_identifier == hopper_identifier:
18 | hopper_code_obj_identity = row[9]
19 | break
20 |
21 | if hopper_code_obj_identity:
22 | cursor.execute(
23 | "insert into access VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
24 | (
25 | "kTCCServiceAppleEvents",
26 | vscode_identifier,
27 | 0,
28 | 1,
29 | 0,
30 | None,
31 | None,
32 | 0,
33 | hopper_identifier,
34 | hopper_code_obj_identity,
35 | None,
36 | int(datetime.datetime.now().timestamp()),
37 | ),
38 | )
39 |
40 | connection.commit()
41 |
--------------------------------------------------------------------------------
/run_hopper.py:
--------------------------------------------------------------------------------
1 | import json
2 | import logging
3 | import subprocess
4 | import time
5 | from http import server
6 | from pathlib import Path
7 |
8 | import requests
9 |
10 | from hopper_proxy import TerminateHopper
11 |
12 | logger = logging.getLogger("hopper_launch")
13 | logger.setLevel(logging.DEBUG)
14 | ch = logging.StreamHandler()
15 | ch.setLevel(logging.DEBUG)
16 | formatter = logging.Formatter("%(asctime)s: %(message)s")
17 | ch.setFormatter(formatter)
18 | logger.addHandler(ch)
19 |
20 | TerminateHopper.kill_hopper()
21 |
22 | hopper_launcher_path = "/Applications/Hopper Disassembler v4.app/Contents/MacOS/hopper"
23 | hopper_path = "/Applications/Hopper Disassembler v4.app/Contents/MacOS/Hopper Disassembler v4"
24 |
25 |
26 | def server_list_documents(port):
27 | endpoint = f"http://localhost:{port}/documents"
28 | response = requests.get(endpoint)
29 | return response.json().get("data")
30 |
31 |
32 | def server_get_doc_filepath(port, document_name):
33 | endpoint = f"http://localhost:{port}/filepath"
34 | try:
35 | response = requests.post(endpoint, data=json.dumps({"document_name": document_name}))
36 | return response.json().get("data")
37 | except Exception as e:
38 | print(e)
39 | return None
40 |
41 |
42 | def _launch_binary_workaround_hopper_bug(binary: Path, command_args):
43 | # Launch Hopper with a test binary and the proxy script
44 | # Work around the "missing loader" bug
45 | for _ in range(2):
46 | try:
47 | subprocess.check_output([hopper_launcher_path, "-A", "-e", binary.as_posix()] + command_args, stderr=subprocess.STDOUT)
48 | break
49 | except subprocess.CalledProcessError as e:
50 | if e.stdout and b"The handler some object is not defined." in e.stdout:
51 | # Workaround the bug
52 | try:
53 | subprocess.check_output([hopper_launcher_path], stderr=subprocess.STDOUT)
54 | except:
55 | pass
56 | time.sleep(1)
57 | else:
58 | print(e.stdout)
59 | raise
60 |
61 |
62 | def _is_binary_fat(binary: Path):
63 | """Is this a FAT macho"""
64 | # Use lipo to determine if the file is FAT
65 | return b"the fat file" in subprocess.check_output(["/usr/bin/lipo", "-info", binary.as_posix()])
66 |
67 |
68 | def launch_server():
69 | """Launch Hopper with a dummy document and start a proxy server."""
70 | # Small dummy binary (TODO: use smaller binary)
71 | dummy_document = Path("lzssdec").resolve()
72 | hopper_args = [
73 | "-l",
74 | "Mach-O",
75 | "--intel-64",
76 | ]
77 | # Launch the hopper server. This server will handle requests for any subsequent Documents that are opened.
78 | # This is basically idempotent - repeat launches will silently fail to bind the server port
79 | _launch_binary_workaround_hopper_bug(dummy_document, hopper_args)
80 |
81 |
82 | def find_hopper_server_port():
83 | """ Find the port that Hopper's server is running on
84 | """
85 | try:
86 | hopper_launch_output = subprocess.check_output([hopper_path], stderr=subprocess.STDOUT)
87 | port = hopper_launch_output.split(b"Hopper already running on port: ")[1]
88 | return int(port)
89 | except:
90 | pass
91 | return None
92 |
93 |
94 | def open_binary_in_hopper(binary: Path, arch_flag):
95 | """Launch a binary in Hopper. (No server is started)"""
96 | hopper_args = [
97 | "-l",
98 | "Mach-O",
99 | arch_flag,
100 | ]
101 | if _is_binary_fat(binary):
102 | # If its FAT, add the correct loader flag
103 | hopper_args += ["-l", "FAT"]
104 | _launch_binary_workaround_hopper_bug(binary, hopper_args)
105 |
106 |
107 | def wait_for_document(port, document_name):
108 | """Wait for a specific Document to become available"""
109 | while True:
110 | try:
111 | documents = server_list_documents(port)
112 | if document_name in documents:
113 | break
114 | except requests.exceptions.ConnectionError:
115 | pass
116 |
117 |
118 | def wait_for_new_document(port, previous_docs):
119 | """Wait for a previously-unknown Document to become available.
120 | previous_docs: Document names that are already known
121 | """
122 | while True:
123 | try:
124 | new_documents = server_list_documents(port)
125 | if len(new_documents) > len(previous_docs):
126 | # Find the new item
127 | new_document = [new_doc for new_doc in new_documents if new_doc not in previous_docs][0]
128 | return new_document
129 | except requests.exceptions.ConnectionError:
130 | pass
131 |
132 |
133 | def wait_for_named_document_with_path(port, document_file_path):
134 | """Wait for a Document to become available that:
135 | 1. Has a real name, which indicates it is not still processing
136 | 2. Has a executablePath that matches the provided document_file_path
137 | """
138 | while True:
139 | try:
140 | new_documents = server_list_documents(port)
141 | for document in new_documents:
142 | # Skip un-named (still analyzing) docs
143 | if "Untitle" in document:
144 | continue
145 | if document_file_path == server_get_doc_filepath(port, document):
146 | return document
147 |
148 | time.sleep(1)
149 |
150 | except requests.exceptions.ConnectionError:
151 | pass
152 |
153 |
154 | testbin_path = Path("/Users/ethanarbuckle/Desktop/decrypt")#Path("/Users/ethanarbuckle/Downloads/app_downloads/Payload 65/app-decrypt-com.cvs.cvspharmacyr1buo3ck.app/CVSOnlineiPhone")
155 | # Launch a dummy document. It will host the server that handles responses for *all* documents
156 | launch_server()
157 |
158 | # Find the port the server is hosting on
159 | server_port = find_hopper_server_port()
160 | if not server_port:
161 | print("failed to find server port!")
162 | exit(0)
163 |
164 | # Wait for the server to launch
165 | wait_for_document(server_port, "lzssdec.hop")
166 | logger.info(f"server launched on port {server_port}")
167 |
168 | # Note the names of the current Hopper documents
169 | current_hopper_docs = server_list_documents(server_port)
170 |
171 | # Open the requested document.
172 | arch_flags = "--aarch64"
173 | open_binary_in_hopper(testbin_path, arch_flags)
174 |
175 | # Wait for the server to acknowledge the new document
176 | # new_doc_name = testbin_path.name + ".hop"
177 | document_name = wait_for_new_document(server_port, current_hopper_docs)
178 | logger.info(f"found new document: {document_name}")
179 | if "Untitle" in document_name:
180 | logger.info("waiting for initial analysis to finish...")
181 | # Wait for a named document to become available
182 | document_name = wait_for_named_document_with_path(server_port, testbin_path.as_posix())
183 |
184 | logger.info(f"document ready: {document_name}")
185 |
--------------------------------------------------------------------------------