mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-04-24 00:00:04 +08:00
#33 Documented Core/
This commit is contained in:
@@ -30,8 +30,14 @@
|
|||||||
#import "GCDWebServerRequest.h"
|
#import "GCDWebServerRequest.h"
|
||||||
#import "GCDWebServerResponse.h"
|
#import "GCDWebServerResponse.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log levels used by GCDWebServer.
|
||||||
|
*
|
||||||
|
* @warning kGCDWebServerLogLevel_Debug is only available if "NDEBUG" is not
|
||||||
|
* defined when building.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(int, GCDWebServerLogLevel) {
|
typedef NS_ENUM(int, GCDWebServerLogLevel) {
|
||||||
kGCDWebServerLogLevel_Debug = 0, // Only available if "NDEBUG" is not defined when building
|
kGCDWebServerLogLevel_Debug = 0,
|
||||||
kGCDWebServerLogLevel_Verbose,
|
kGCDWebServerLogLevel_Verbose,
|
||||||
kGCDWebServerLogLevel_Info,
|
kGCDWebServerLogLevel_Info,
|
||||||
kGCDWebServerLogLevel_Warning,
|
kGCDWebServerLogLevel_Warning,
|
||||||
@@ -39,88 +45,420 @@ typedef NS_ENUM(int, GCDWebServerLogLevel) {
|
|||||||
kGCDWebServerLogLevel_Exception,
|
kGCDWebServerLogLevel_Exception,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerMatchBlock is called for every handler added to the
|
||||||
|
* GCDWebServer whenever a new HTTP request has started (i.e. HTTP headers have
|
||||||
|
* been received). The block is passed the basic info for the request (HTTP method,
|
||||||
|
* URL, headers...) and must decide if it wants to handle it or not.
|
||||||
|
*
|
||||||
|
* If the handler can handle the request, the block must return a new
|
||||||
|
* GCDWebServerRequest instance created with the same basic info.
|
||||||
|
* Otherwise, it simply returns nil.
|
||||||
|
*/
|
||||||
typedef GCDWebServerRequest* (^GCDWebServerMatchBlock)(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery);
|
typedef GCDWebServerRequest* (^GCDWebServerMatchBlock)(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerProcessBlock is called after the HTTP request has been fully
|
||||||
|
* received (i.e. the entire HTTP body has been read). THe block is passed the
|
||||||
|
* GCDWebServerRequest created at the previous step by the GCDWebServerMatchBlock.
|
||||||
|
*
|
||||||
|
* The block must return a GCDWebServerResponse or nil on error, which will
|
||||||
|
* result in a 500 HTTP status code returned to the client. It's however
|
||||||
|
* recommended to return a GCDWebServerErrorResponse on error so more useful
|
||||||
|
* information can be returned to the client.
|
||||||
|
*/
|
||||||
typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* request);
|
typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* request);
|
||||||
|
|
||||||
extern NSString* const GCDWebServerOption_Port; // NSNumber / NSUInteger (default is 0 i.e. use a random port)
|
/**
|
||||||
extern NSString* const GCDWebServerOption_BonjourName; // NSString (default is empty string i.e. use computer name)
|
* The port used by the GCDWebServer (NSNumber / NSUInteger).
|
||||||
extern NSString* const GCDWebServerOption_MaxPendingConnections; // NSNumber / NSUInteger (default is 16)
|
*
|
||||||
extern NSString* const GCDWebServerOption_ServerName; // NSString (default is server class name)
|
* Default value is 0 i.e. let the OS pick a random port.
|
||||||
extern NSString* const GCDWebServerOption_AuthenticationMethod; // One of "GCDWebServerAuthenticationMethod_..." (default is nil i.e. no authentication)
|
*/
|
||||||
extern NSString* const GCDWebServerOption_AuthenticationRealm; // NSString (default is server name)
|
extern NSString* const GCDWebServerOption_Port;
|
||||||
extern NSString* const GCDWebServerOption_AuthenticationAccounts; // NSDictionary of username / password (default is nil i.e. no accounts)
|
|
||||||
extern NSString* const GCDWebServerOption_ConnectionClass; // Subclass of GCDWebServerConnection (default is GCDWebServerConnection class)
|
/**
|
||||||
extern NSString* const GCDWebServerOption_AutomaticallyMapHEADToGET; // NSNumber / BOOL (default is YES)
|
* The Bonjour name used by the GCDWebServer (NSString).
|
||||||
extern NSString* const GCDWebServerOption_ConnectedStateCoalescingInterval; // NSNumber / double (default is 1.0 seconds - set to <=0.0 to disable coaslescing of -webServerDidConnect: / -webServerDidDisconnect:)
|
*
|
||||||
|
* Default value is an empty string i.e. use the computer / device name.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_BonjourName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of incoming HTTP requests that can be queued waiting to
|
||||||
|
* be handled before new ones are dropped (NSNumber / NSUInteger).
|
||||||
|
*
|
||||||
|
* Default value is 16.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_MaxPendingConnections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value for "Server" HTTP header used by the GCDWebServer (NSString).
|
||||||
|
*
|
||||||
|
* Default value is the GCDWebServer class name.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_ServerName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authentication method used by the GCDWebServer
|
||||||
|
* (one of "GCDWebServerAuthenticationMethod_...").
|
||||||
|
*
|
||||||
|
* Default value is nil i.e. authentication disabled.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_AuthenticationMethod;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authentication realm used by the GCDWebServer (NSString).
|
||||||
|
*
|
||||||
|
* Default value is the same as GCDWebServerOption_ServerName.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_AuthenticationRealm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The authentication accounts used by the GCDWebServer
|
||||||
|
* (NSDictionary of username / password pairs).
|
||||||
|
*
|
||||||
|
* Default value is nil i.e. no accounts.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_AuthenticationAccounts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class used by the GCDWebServer when instantiating GCDWebServerConnection
|
||||||
|
* (subclass of GCDWebServerConnection).
|
||||||
|
*
|
||||||
|
* Default value is GCDWebServerConnection class.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_ConnectionClass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allow the GCDWebServer to pretend "HEAD" requests are actually "GET" ones
|
||||||
|
* and automatically discard the HTTP body of the response (NSNumber / BOOL).
|
||||||
|
*
|
||||||
|
* Default value is YES.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_AutomaticallyMapHEADToGET;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The interval expressed in seconds used by the GCDWebServer to decide how to
|
||||||
|
* coalesce calls to -webServerDidConnect: and -webServerDidDisconnect:
|
||||||
|
* (NSNumber / double). Coalescing will be disabled if the interval is <= 0.0.
|
||||||
|
*
|
||||||
|
* Default value is 1.0 second.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_ConnectedStateCoalescingInterval;
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
extern NSString* const GCDWebServerOption_AutomaticallySuspendInBackground; // NSNumber / BOOL (default is YES)
|
|
||||||
|
/**
|
||||||
|
* Enables the GCDWebServer to automatically suspend itself (as if -stop was
|
||||||
|
* called) when the iOS app goes into the background and the last
|
||||||
|
* GCDWebServerConnection is closed, then resume itself (as if -start was called)
|
||||||
|
* when the iOS app comes back to the foreground (NSNumber / BOOL).
|
||||||
|
*
|
||||||
|
* See the README.md file for more information about this option.
|
||||||
|
*
|
||||||
|
* Default value is YES.
|
||||||
|
*
|
||||||
|
* @warning The running property will be NO while the GCDWebServer is suspended.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerOption_AutomaticallySuspendInBackground;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern NSString* const GCDWebServerAuthenticationMethod_Basic; // Not recommended as password is sent in clear
|
/**
|
||||||
|
* HTTP Basic Authentication scheme (see https://tools.ietf.org/html/rfc2617).
|
||||||
|
*
|
||||||
|
* @warning Use of this method is not recommended as the passwords are sent in clear.
|
||||||
|
*/
|
||||||
|
extern NSString* const GCDWebServerAuthenticationMethod_Basic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HTTP Digest Access Authentication scheme (see https://tools.ietf.org/html/rfc2617).
|
||||||
|
*/
|
||||||
extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
|
extern NSString* const GCDWebServerAuthenticationMethod_DigestAccess;
|
||||||
|
|
||||||
@class GCDWebServer;
|
@class GCDWebServer;
|
||||||
|
|
||||||
// These methods are always called on main thread
|
/**
|
||||||
|
* Delegate methods for GCDWebServer.
|
||||||
|
*
|
||||||
|
* @warning These methods are always called on the main thread in a serialized way.
|
||||||
|
*/
|
||||||
@protocol GCDWebServerDelegate <NSObject>
|
@protocol GCDWebServerDelegate <NSObject>
|
||||||
@optional
|
@optional
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after the server has succesfully started.
|
||||||
|
*/
|
||||||
- (void)webServerDidStart:(GCDWebServer*)server;
|
- (void)webServerDidStart:(GCDWebServer*)server;
|
||||||
- (void)webServerDidConnect:(GCDWebServer*)server; // Called when first connection is opened
|
|
||||||
- (void)webServerDidDisconnect:(GCDWebServer*)server; // Called when last connection is closed
|
/**
|
||||||
|
* This method is called when the first GCDWebServerConnection is opened by the
|
||||||
|
* server to serve a series of HTTP requests. A series is ongoing as long as
|
||||||
|
* new HTTP requests keep coming (and new GCDWebServerConnection instances keep
|
||||||
|
* being opened), before the last HTTP request has been responded to (and the
|
||||||
|
* corresponding last GCDWebServerConnection closed).
|
||||||
|
*/
|
||||||
|
- (void)webServerDidConnect:(GCDWebServer*)server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called when the last GCDWebServerConnection is closed after
|
||||||
|
* the server has served a series of HTTP requests.
|
||||||
|
*
|
||||||
|
* The GCDWebServerOption_ConnectedStateCoalescingInterval option can be used
|
||||||
|
* to have the server wait some extra delay before considering that the series
|
||||||
|
* of HTTP requests has ended (in case there some latency between consecutive
|
||||||
|
* requests). This effectively coalesces the calls to -webServerDidConnect:
|
||||||
|
* and -webServerDidDisconnect:.
|
||||||
|
*/
|
||||||
|
- (void)webServerDidDisconnect:(GCDWebServer*)server;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after the server has stopped.
|
||||||
|
*/
|
||||||
- (void)webServerDidStop:(GCDWebServer*)server;
|
- (void)webServerDidStop:(GCDWebServer*)server;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServer class manages the socket that listens for HTTP requests and
|
||||||
|
* the list of handlers used to respond to them.
|
||||||
|
*
|
||||||
|
* See the README.md file for more information about the architecture of GCDWebServer.
|
||||||
|
*/
|
||||||
@interface GCDWebServer : NSObject
|
@interface GCDWebServer : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the delegate for the server.
|
||||||
|
*/
|
||||||
@property(nonatomic, assign) id<GCDWebServerDelegate> delegate;
|
@property(nonatomic, assign) id<GCDWebServerDelegate> delegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the server is currently running.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly, getter=isRunning) BOOL running;
|
@property(nonatomic, readonly, getter=isRunning) BOOL running;
|
||||||
@property(nonatomic, readonly) NSUInteger port; // Only non-zero if running
|
|
||||||
@property(nonatomic, readonly) NSString* bonjourName; // Only non-nil if Bonjour registration is active
|
/**
|
||||||
|
* Returns the port used by the server.
|
||||||
|
*
|
||||||
|
* @warning This property is only valid if the server is running.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSUInteger port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Bonjour name in used by the server.
|
||||||
|
*
|
||||||
|
* @warning This property is only valid if the server is running and Bonjour
|
||||||
|
* registration has successfully completed, which can take up to a few seconds.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSString* bonjourName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is the designated initializer for the class.
|
||||||
|
*/
|
||||||
- (instancetype)init;
|
- (instancetype)init;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a handler to the server to handle incoming HTTP requests.
|
||||||
|
* Handlers are called in a LIFO queue, so the latest added handler overrides
|
||||||
|
* any previously added ones.
|
||||||
|
*
|
||||||
|
* @warning Addling handlers while the GCDWebServer is running is not allowed.
|
||||||
|
*/
|
||||||
- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock;
|
- (void)addHandlerWithMatchBlock:(GCDWebServerMatchBlock)matchBlock processBlock:(GCDWebServerProcessBlock)processBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all handlers previously added to the server.
|
||||||
|
*
|
||||||
|
* @warning Removing handlers while the GCDWebServer is running is not allowed.
|
||||||
|
*/
|
||||||
- (void)removeAllHandlers;
|
- (void)removeAllHandlers;
|
||||||
|
|
||||||
- (BOOL)start; // Default is port 8080 (OS X & iOS Simulator) or 80 (iOS) and computer / device name for Bonjour
|
/**
|
||||||
- (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name; // Pass nil name to disable Bonjour or empty string to use computer name
|
* Starts the server on port 8080 (OS X & iOS Simulator) or port 80 (iOS)
|
||||||
|
* using the computer / device name for as the Bonjour name.
|
||||||
|
*
|
||||||
|
* Returns NO if the server failed to start.
|
||||||
|
*/
|
||||||
|
- (BOOL)start;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the server on a given port and with a specific Bonjour name.
|
||||||
|
* Pass a nil Bonjour name to disable Bonjour entirely or an empty string to
|
||||||
|
* use the computer / device name.
|
||||||
|
*
|
||||||
|
* Returns NO if the server failed to start.
|
||||||
|
*/
|
||||||
|
- (BOOL)startWithPort:(NSUInteger)port bonjourName:(NSString*)name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the server with explicit options. This method is the designated way
|
||||||
|
* to start the server.
|
||||||
|
*
|
||||||
|
* Returns NO if the server failed to start.
|
||||||
|
*/
|
||||||
- (BOOL)startWithOptions:(NSDictionary*)options;
|
- (BOOL)startWithOptions:(NSDictionary*)options;
|
||||||
- (void)stop; // Does not abort any currently opened connections
|
|
||||||
|
/**
|
||||||
|
* Stops the server and prevents it to accepts new HTTP requests.
|
||||||
|
*
|
||||||
|
* @warning Stopping the server does not abort GCDWebServerConnection instances
|
||||||
|
* handling already received HTTP requests. These connections will continue to
|
||||||
|
* execute until the corresponding requests and responses are completed.
|
||||||
|
*/
|
||||||
|
- (void)stop;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GCDWebServer (Extensions)
|
@interface GCDWebServer (Extensions)
|
||||||
@property(nonatomic, readonly) NSURL* serverURL; // Only non-nil if server is running
|
|
||||||
@property(nonatomic, readonly) NSURL* bonjourServerURL; // Only non-nil if server is running and Bonjour registration is active
|
/**
|
||||||
|
* Returns the server's URL.
|
||||||
|
*
|
||||||
|
* @warning This property is only valid if the server is running.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSURL* serverURL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the server's Bonjour URL.
|
||||||
|
*
|
||||||
|
* @warning This property is only valid if the server is running and Bonjour
|
||||||
|
* registration has successfully completed, which can take up to a few seconds.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSURL* bonjourServerURL;
|
||||||
|
|
||||||
#if !TARGET_OS_IPHONE
|
#if !TARGET_OS_IPHONE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the server synchronously using -startWithPort:bonjourName: until a
|
||||||
|
* SIGINT signal is received i.e. Ctrl-C. This method is intended to be used
|
||||||
|
* by command line tools.
|
||||||
|
*
|
||||||
|
* Returns NO if the server failed to start.
|
||||||
|
*
|
||||||
|
* @warning This method must be used from the main thread only.
|
||||||
|
*/
|
||||||
- (BOOL)runWithPort:(NSUInteger)port bonjourName:(NSString*)name;
|
- (BOOL)runWithPort:(NSUInteger)port bonjourName:(NSString*)name;
|
||||||
- (BOOL)runWithOptions:(NSDictionary*)options; // Starts then automatically stops on SIGINT i.e. Ctrl-C (use on main thread only)
|
|
||||||
|
/**
|
||||||
|
* Runs the server synchronously using -startWithOptions: until a SIGINT signal
|
||||||
|
* is received i.e. Ctrl-C. This method is intended to be used by command line
|
||||||
|
* tools.
|
||||||
|
*
|
||||||
|
* Returns NO if the server failed to start.
|
||||||
|
*
|
||||||
|
* @warning This method must be used from the main thread only.
|
||||||
|
*/
|
||||||
|
- (BOOL)runWithOptions:(NSDictionary*)options;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GCDWebServer (Handlers)
|
@interface GCDWebServer (Handlers)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a default handler to the server to handle all incoming HTTP requests
|
||||||
|
* with a given HTTP method.
|
||||||
|
*/
|
||||||
- (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block;
|
- (void)addDefaultHandlerForMethod:(NSString*)method requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block;
|
||||||
- (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block; // Path is case-insensitive
|
|
||||||
- (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block; // Regular expression is case-insensitive
|
/**
|
||||||
|
* Adds a handler to the server to handle incoming HTTP requests with a given
|
||||||
|
* HTTP method and a specific case-insensitive path.
|
||||||
|
*/
|
||||||
|
- (void)addHandlerForMethod:(NSString*)method path:(NSString*)path requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a handler to the server to handle incoming HTTP requests with a given
|
||||||
|
* HTTP method and a path matching a case-insensitive regular expression.
|
||||||
|
*/
|
||||||
|
- (void)addHandlerForMethod:(NSString*)method pathRegex:(NSString*)regex requestClass:(Class)aClass processBlock:(GCDWebServerProcessBlock)block;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GCDWebServer (GETHandlers)
|
@interface GCDWebServer (GETHandlers)
|
||||||
- (void)addGETHandlerForPath:(NSString*)path staticData:(NSData*)staticData contentType:(NSString*)contentType cacheAge:(NSUInteger)cacheAge; // Path is case-insensitive
|
|
||||||
- (void)addGETHandlerForPath:(NSString*)path filePath:(NSString*)filePath isAttachment:(BOOL)isAttachment cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests; // Path is case-insensitive
|
/**
|
||||||
- (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)directoryPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests; // Base path is recursive and case-sensitive
|
* Adds a handler to the server to respond to incoming "GET" HTTP requests
|
||||||
|
* with a specific case-insensitive path with in-memory data.
|
||||||
|
*/
|
||||||
|
- (void)addGETHandlerForPath:(NSString*)path staticData:(NSData*)staticData contentType:(NSString*)contentType cacheAge:(NSUInteger)cacheAge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a handler to the server to respond to incoming "GET" HTTP requests
|
||||||
|
* with a specific case-insensitive path with a file.
|
||||||
|
*/
|
||||||
|
- (void)addGETHandlerForPath:(NSString*)path filePath:(NSString*)filePath isAttachment:(BOOL)isAttachment cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a handler to the server to respond to incoming "GET" HTTP requests
|
||||||
|
* with a case-insensitive path inside a base path with the corresponding file
|
||||||
|
* inside a local directory. If no local file matches the request path, a 401
|
||||||
|
* HTTP status code is returned to the client.
|
||||||
|
*
|
||||||
|
* The "indexFilename" argument allows to specify an "index" file name to use
|
||||||
|
* when the request path corresponds to a directory.
|
||||||
|
*/
|
||||||
|
- (void)addGETHandlerForBasePath:(NSString*)basePath directoryPath:(NSString*)directoryPath indexFilename:(NSString*)indexFilename cacheAge:(NSUInteger)cacheAge allowRangeRequests:(BOOL)allowRangeRequests;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GCDWebServer (Logging)
|
@interface GCDWebServer (Logging)
|
||||||
|
|
||||||
#ifndef __GCDWEBSERVER_LOGGING_HEADER__
|
#ifndef __GCDWEBSERVER_LOGGING_HEADER__
|
||||||
+ (void)setLogLevel:(GCDWebServerLogLevel)level; // Default level is DEBUG or INFO if "NDEBUG" is defined when building (it can also be set at runtime with the "logLevel" environment variable)
|
|
||||||
|
/**
|
||||||
|
* Sets the current log level below which logged messages are discarded.
|
||||||
|
*
|
||||||
|
* The default level is either DEBUG or INFO if "NDEBUG" is defined at build-time.
|
||||||
|
* It can also be set at runtime with the "logLevel" environment variable.
|
||||||
|
*/
|
||||||
|
+ (void)setLogLevel:(GCDWebServerLogLevel)level;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message with the kGCDWebServerLogLevel_Verbose level.
|
||||||
|
*/
|
||||||
- (void)logVerbose:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
- (void)logVerbose:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message with the kGCDWebServerLogLevel_Info level.
|
||||||
|
*/
|
||||||
- (void)logInfo:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
- (void)logInfo:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message with the kGCDWebServerLogLevel_Warning level.
|
||||||
|
*/
|
||||||
- (void)logWarning:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
- (void)logWarning:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs a message with the kGCDWebServerLogLevel_Error level.
|
||||||
|
*/
|
||||||
- (void)logError:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
- (void)logError:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2);
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||||
|
|
||||||
@interface GCDWebServer (Testing)
|
@interface GCDWebServer (Testing)
|
||||||
@property(nonatomic, getter=isRecordingEnabled) BOOL recordingEnabled; // Creates files in the current directory containing the raw data for all requests and responses (directory most NOT contain prior recordings)
|
|
||||||
- (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path; // Returns number of failed tests or -1 if server failed to start
|
/**
|
||||||
|
* Activates recording of HTTP requests and responses which create files in the
|
||||||
|
* current directory containing the raw data for all requests and responses.
|
||||||
|
*
|
||||||
|
* @warning The current directory must not contain any prior recording files.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, getter=isRecordingEnabled) BOOL recordingEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs tests by playing back pre-recorded HTTP requests in the given directory
|
||||||
|
* and comparing the generated responses with the pre-recorded ones.
|
||||||
|
*
|
||||||
|
* Returns the number of failed tests or -1 if server failed to start.
|
||||||
|
*/
|
||||||
|
- (NSInteger)runTestsWithOptions:(NSDictionary*)options inDirectory:(NSString*)path;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -29,24 +29,132 @@
|
|||||||
|
|
||||||
@class GCDWebServerHandler;
|
@class GCDWebServerHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerConnection class is instantiated by GCDWebServer to handle
|
||||||
|
* each new HTTP connection. Each instance stays alive until the connection is
|
||||||
|
* closed.
|
||||||
|
*
|
||||||
|
* You cannot use this class directly, but it is made public so you can
|
||||||
|
* subclass it to override some hooks. Use the GCDWebServerOption_ConnectionClass
|
||||||
|
* option for GCDWebServer to install your custom subclass.
|
||||||
|
*
|
||||||
|
* @warning The GCDWebServerConnection retains the GCDWebServer
|
||||||
|
* until the connection is closed.
|
||||||
|
*/
|
||||||
@interface GCDWebServerConnection : NSObject
|
@interface GCDWebServerConnection : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the GCDWebServer that owns the connection.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) GCDWebServer* server;
|
@property(nonatomic, readonly) GCDWebServer* server;
|
||||||
@property(nonatomic, readonly) NSData* localAddressData; // struct sockaddr
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the local peer (i.e. server) of the connection
|
||||||
|
* as a raw "struct sockaddr".
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSData* localAddressData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the local peer (i.e. server) of the connection
|
||||||
|
* as a dotted string.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSString* localAddressString;
|
@property(nonatomic, readonly) NSString* localAddressString;
|
||||||
@property(nonatomic, readonly) NSData* remoteAddressData; // struct sockaddr
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the remote peer (i.e. client) of the connection
|
||||||
|
* as a raw "struct sockaddr".
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSData* remoteAddressData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address of the remote peer (i.e. client) of the connection
|
||||||
|
* as a dotted string.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSString* remoteAddressString;
|
@property(nonatomic, readonly) NSString* remoteAddressString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of bytes received from the remote peer (i.e. client)
|
||||||
|
* so far.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSUInteger totalBytesRead;
|
@property(nonatomic, readonly) NSUInteger totalBytesRead;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total number of bytes sent to the remote peer (i.e. client) so far.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSUInteger totalBytesWritten;
|
@property(nonatomic, readonly) NSUInteger totalBytesWritten;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
// These methods can be called from any thread
|
/**
|
||||||
|
* Hooks to customize the behavior of GCDWebServer HTTP connections.
|
||||||
|
*
|
||||||
|
* @warning These methods can be called on any GCD thread.
|
||||||
|
* Be sure to also call "super" when overriding them.
|
||||||
|
*/
|
||||||
@interface GCDWebServerConnection (Subclassing)
|
@interface GCDWebServerConnection (Subclassing)
|
||||||
- (BOOL)open; // Return NO to reject connection e.g. after validating local or remote addresses
|
|
||||||
- (void)didReadBytes:(const void*)bytes length:(NSUInteger)length; // Called after data has been read from the connection
|
/**
|
||||||
- (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length; // Called after data has been written to the connection
|
* This method is called when the connection is opened.
|
||||||
- (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request; // Called before request is processed to return an override response bypassing processing or nil to continue - Default implementation checks authentication if applicable
|
* Return NO to reject the connection e.g. after validating the local
|
||||||
- (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock:(GCDWebServerProcessBlock)block; // Only called if the request can be processed
|
* or remote address.
|
||||||
- (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request; // Default implementation replaces any response matching the "ETag" or "Last-Modified-Date" header of the request by a barebone "Not-Modified" (304) one
|
*/
|
||||||
- (void)abortRequest:(GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode; // If request headers were malformed, "request" will be nil
|
- (BOOL)open;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called whenever data has been received
|
||||||
|
* from the remote peer (i.e. client).
|
||||||
|
*/
|
||||||
|
- (void)didReadBytes:(const void*)bytes length:(NSUInteger)length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called whenever data has been sent
|
||||||
|
* to the remote peer (i.e. client).
|
||||||
|
*/
|
||||||
|
- (void)didWriteBytes:(const void*)bytes length:(NSUInteger)length;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assuming a valid request was received, this method is called before
|
||||||
|
* the request is processed.
|
||||||
|
*
|
||||||
|
* Return a non-nil GCDWebServerResponse to bypass the request processing entirely.
|
||||||
|
*
|
||||||
|
* The default implementation checks for HTTP authentication if applicable
|
||||||
|
* and returns a barebone 401 status code response if authentication failed.
|
||||||
|
*/
|
||||||
|
- (GCDWebServerResponse*)preflightRequest:(GCDWebServerRequest*)request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assuming a valid request was received and -preflightRequest: returned nil,
|
||||||
|
* this method is called to process the request.
|
||||||
|
*/
|
||||||
|
- (GCDWebServerResponse*)processRequest:(GCDWebServerRequest*)request withBlock:(GCDWebServerProcessBlock)block;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assuming a valid request was received and either -preflightRequest:
|
||||||
|
* or -processRequest:withBlock: returned a non-nil GCDWebServerResponse,
|
||||||
|
* this method is called to override the response.
|
||||||
|
*
|
||||||
|
* You can either modify the current response and return it, or return a
|
||||||
|
* completely different one.
|
||||||
|
*
|
||||||
|
* The default implementation replaces any response matching the "ETag" or
|
||||||
|
* "Last-Modified-Date" header of the request by a barebone "Not-Modified" (304)
|
||||||
|
* one.
|
||||||
|
*/
|
||||||
|
- (GCDWebServerResponse*)overrideResponse:(GCDWebServerResponse*)response forRequest:(GCDWebServerRequest*)request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called if any error happens while validing or processing
|
||||||
|
* the request or no GCDWebServerResponse is generated.
|
||||||
|
*
|
||||||
|
* @warning If the request was invalid (e.g. the HTTP headers were malformed),
|
||||||
|
* the "request" argument will be nil.
|
||||||
|
*/
|
||||||
|
- (void)abortRequest:(GCDWebServerRequest*)request withStatusCode:(NSInteger)statusCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the connection is closed.
|
||||||
|
*/
|
||||||
- (void)close;
|
- (void)close;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -31,14 +31,68 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a file extension to the corresponding MIME type.
|
||||||
|
* If there is no match, "application/octet-stream" is returned.
|
||||||
|
*/
|
||||||
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension);
|
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add percent-escapes to a string so it can be used in a URL.
|
||||||
|
* The legal characters ":@/?&=+" are also escaped to ensure compatibility
|
||||||
|
* with URL encoded forms and URL queries.
|
||||||
|
*/
|
||||||
NSString* GCDWebServerEscapeURLString(NSString* string);
|
NSString* GCDWebServerEscapeURLString(NSString* string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescapes a URL percent-encoded string.
|
||||||
|
*/
|
||||||
NSString* GCDWebServerUnescapeURLString(NSString* string);
|
NSString* GCDWebServerUnescapeURLString(NSString* string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the unescaped names and values
|
||||||
|
* from a "application/x-www-form-urlencoded" form.
|
||||||
|
* http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
|
||||||
|
*/
|
||||||
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
|
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
|
||||||
NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of primary connected service on OS X or of WiFi interface on iOS if connected
|
|
||||||
|
/**
|
||||||
|
* OS X: Returns the IPv4 address as a dotted string of the primary connected
|
||||||
|
* service or nil if not available.
|
||||||
|
* iOS: Returns the IPv4 address as a dotted string of the WiFi interface
|
||||||
|
* if connected or nil otherwise.
|
||||||
|
*/
|
||||||
|
NSString* GCDWebServerGetPrimaryIPv4Address();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a date into a string using RFC822 formatting.
|
||||||
|
* https://tools.ietf.org/html/rfc822#section-5
|
||||||
|
* https://tools.ietf.org/html/rfc1123#section-5.2.14
|
||||||
|
*/
|
||||||
NSString* GCDWebServerFormatRFC822(NSDate* date);
|
NSString* GCDWebServerFormatRFC822(NSDate* date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a RFC822 formatted string into a date.
|
||||||
|
* https://tools.ietf.org/html/rfc822#section-5
|
||||||
|
* https://tools.ietf.org/html/rfc1123#section-5.2.14
|
||||||
|
*
|
||||||
|
* @warning Timezones are not supported at this time.
|
||||||
|
*/
|
||||||
NSDate* GCDWebServerParseRFC822(NSString* string);
|
NSDate* GCDWebServerParseRFC822(NSString* string);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a date into a string using IOS 8601 formatting.
|
||||||
|
* http://tools.ietf.org/html/rfc3339#section-5.6
|
||||||
|
*/
|
||||||
NSString* GCDWebServerFormatISO8601(NSDate* date);
|
NSString* GCDWebServerFormatISO8601(NSDate* date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a ISO 8601 formatted string into a date.
|
||||||
|
* http://tools.ietf.org/html/rfc3339#section-5.6
|
||||||
|
*
|
||||||
|
* @warning Only "calendar" variant is supported at this time and timezones
|
||||||
|
* are not supported either.
|
||||||
|
*/
|
||||||
NSDate* GCDWebServerParseISO8601(NSString* string);
|
NSDate* GCDWebServerParseISO8601(NSString* string);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ static NSDateFormatter* _dateFormatterRFC822 = nil;
|
|||||||
static NSDateFormatter* _dateFormatterISO8601 = nil;
|
static NSDateFormatter* _dateFormatterISO8601 = nil;
|
||||||
static dispatch_queue_t _dateFormatterQueue = NULL;
|
static dispatch_queue_t _dateFormatterQueue = NULL;
|
||||||
|
|
||||||
// HTTP/1.1 server must use RFC822
|
// TODO: Handle RFC 850 and ANSI C's asctime() format
|
||||||
// TODO: Handle RFC 850 and ANSI C's asctime() format (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3)
|
|
||||||
void GCDWebServerInitializeFunctions() {
|
void GCDWebServerInitializeFunctions() {
|
||||||
DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread
|
DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread
|
||||||
if (_dateFormatterRFC822 == nil) {
|
if (_dateFormatterRFC822 == nil) {
|
||||||
@@ -187,7 +186,6 @@ NSString* GCDWebServerUnescapeURLString(NSString* string) {
|
|||||||
return ARC_BRIDGE_RELEASE(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
|
return ARC_BRIDGE_RELEASE(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, (CFStringRef)string, CFSTR(""), kCFStringEncodingUTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
|
|
||||||
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
|
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form) {
|
||||||
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
|
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
|
||||||
NSScanner* scanner = [[NSScanner alloc] initWithString:form];
|
NSScanner* scanner = [[NSScanner alloc] initWithString:form];
|
||||||
|
|||||||
@@ -30,12 +30,18 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constants for "informational" HTTP status codes.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSInteger, GCDWebServerInformationalHTTPStatusCode) {
|
typedef NS_ENUM(NSInteger, GCDWebServerInformationalHTTPStatusCode) {
|
||||||
kGCDWebServerHTTPStatusCode_Continue = 100,
|
kGCDWebServerHTTPStatusCode_Continue = 100,
|
||||||
kGCDWebServerHTTPStatusCode_SwitchingProtocols = 101,
|
kGCDWebServerHTTPStatusCode_SwitchingProtocols = 101,
|
||||||
kGCDWebServerHTTPStatusCode_Processing = 102
|
kGCDWebServerHTTPStatusCode_Processing = 102
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constants for "successful" HTTP status codes.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSInteger, GCDWebServerSuccessfulHTTPStatusCode) {
|
typedef NS_ENUM(NSInteger, GCDWebServerSuccessfulHTTPStatusCode) {
|
||||||
kGCDWebServerHTTPStatusCode_OK = 200,
|
kGCDWebServerHTTPStatusCode_OK = 200,
|
||||||
kGCDWebServerHTTPStatusCode_Created = 201,
|
kGCDWebServerHTTPStatusCode_Created = 201,
|
||||||
@@ -48,6 +54,9 @@ typedef NS_ENUM(NSInteger, GCDWebServerSuccessfulHTTPStatusCode) {
|
|||||||
kGCDWebServerHTTPStatusCode_AlreadyReported = 208
|
kGCDWebServerHTTPStatusCode_AlreadyReported = 208
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constants for "redirection" HTTP status codes.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSInteger, GCDWebServerRedirectionHTTPStatusCode) {
|
typedef NS_ENUM(NSInteger, GCDWebServerRedirectionHTTPStatusCode) {
|
||||||
kGCDWebServerHTTPStatusCode_MultipleChoices = 300,
|
kGCDWebServerHTTPStatusCode_MultipleChoices = 300,
|
||||||
kGCDWebServerHTTPStatusCode_MovedPermanently = 301,
|
kGCDWebServerHTTPStatusCode_MovedPermanently = 301,
|
||||||
@@ -59,6 +68,9 @@ typedef NS_ENUM(NSInteger, GCDWebServerRedirectionHTTPStatusCode) {
|
|||||||
kGCDWebServerHTTPStatusCode_PermanentRedirect = 308
|
kGCDWebServerHTTPStatusCode_PermanentRedirect = 308
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constants for "client error" HTTP status codes.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSInteger, GCDWebServerClientErrorHTTPStatusCode) {
|
typedef NS_ENUM(NSInteger, GCDWebServerClientErrorHTTPStatusCode) {
|
||||||
kGCDWebServerHTTPStatusCode_BadRequest = 400,
|
kGCDWebServerHTTPStatusCode_BadRequest = 400,
|
||||||
kGCDWebServerHTTPStatusCode_Unauthorized = 401,
|
kGCDWebServerHTTPStatusCode_Unauthorized = 401,
|
||||||
@@ -87,6 +99,9 @@ typedef NS_ENUM(NSInteger, GCDWebServerClientErrorHTTPStatusCode) {
|
|||||||
kGCDWebServerHTTPStatusCode_RequestHeaderFieldsTooLarge = 431
|
kGCDWebServerHTTPStatusCode_RequestHeaderFieldsTooLarge = 431
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience constants for "server error" HTTP status codes.
|
||||||
|
*/
|
||||||
typedef NS_ENUM(NSInteger, GCDWebServerServerErrorHTTPStatusCode) {
|
typedef NS_ENUM(NSInteger, GCDWebServerServerErrorHTTPStatusCode) {
|
||||||
kGCDWebServerHTTPStatusCode_InternalServerError = 500,
|
kGCDWebServerHTTPStatusCode_InternalServerError = 500,
|
||||||
kGCDWebServerHTTPStatusCode_NotImplemented = 501,
|
kGCDWebServerHTTPStatusCode_NotImplemented = 501,
|
||||||
|
|||||||
@@ -27,25 +27,140 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This protocol is used by the GCDWebServerConnection to communicate with
|
||||||
|
* the GCDWebServerRequest and write the received HTTP body data.
|
||||||
|
*
|
||||||
|
* Note that multiple GCDWebServerBodyWriter objects can be chained together
|
||||||
|
* internally e.g. to automatically decode gzip encoded content before
|
||||||
|
* passing it on to the GCDWebServerRequest.
|
||||||
|
*
|
||||||
|
* @warning These methods can be called on any GCD thread.
|
||||||
|
*/
|
||||||
@protocol GCDWebServerBodyWriter <NSObject>
|
@protocol GCDWebServerBodyWriter <NSObject>
|
||||||
- (BOOL)open:(NSError**)error; // Return NO on error ("error" is guaranteed to be non-NULL)
|
|
||||||
- (BOOL)writeData:(NSData*)data error:(NSError**)error; // Return NO on error ("error" is guaranteed to be non-NULL)
|
/**
|
||||||
- (BOOL)close:(NSError**)error; // Return NO on error ("error" is guaranteed to be non-NULL)
|
* This method is called before any body data is received.
|
||||||
|
*
|
||||||
|
* It should return YES on success or NO on failure and set the "error" argument
|
||||||
|
* which is guaranteed to be non-NULL.
|
||||||
|
*/
|
||||||
|
- (BOOL)open:(NSError**)error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called whenever body data has been received.
|
||||||
|
*
|
||||||
|
* It should return YES on success or NO on failure and set the "error" argument
|
||||||
|
* which is guaranteed to be non-NULL.
|
||||||
|
*/
|
||||||
|
- (BOOL)writeData:(NSData*)data error:(NSError**)error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after all body data has been received.
|
||||||
|
*
|
||||||
|
* It should return YES on success or NO on failure and set the "error" argument
|
||||||
|
* which is guaranteed to be non-NULL.
|
||||||
|
*/
|
||||||
|
- (BOOL)close:(NSError**)error;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerRequest class is instantiated by the GCDWebServerConnection
|
||||||
|
* after the HTTP headers have been received. Each instance wraps a single HTTP
|
||||||
|
* request. If a body is present, the methods from the GCDWebServerBodyWriter
|
||||||
|
* protocol will be called by the GCDWebServerConnection to receive it.
|
||||||
|
*
|
||||||
|
* The default implementation of the GCDWebServerBodyWriter protocol on the class
|
||||||
|
* simply ignores the body data.
|
||||||
|
*
|
||||||
|
* @warning GCDWebServerRequest instances can be created and used on any GCD thread.
|
||||||
|
*/
|
||||||
@interface GCDWebServerRequest : NSObject <GCDWebServerBodyWriter>
|
@interface GCDWebServerRequest : NSObject <GCDWebServerBodyWriter>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP method for the request.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSString* method;
|
@property(nonatomic, readonly) NSString* method;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL for the request.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSURL* URL;
|
@property(nonatomic, readonly) NSURL* URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the HTTP headers for the request.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSDictionary* headers;
|
@property(nonatomic, readonly) NSDictionary* headers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path component of the URL for the request.
|
||||||
|
*/
|
||||||
@property(nonatomic, readonly) NSString* path;
|
@property(nonatomic, readonly) NSString* path;
|
||||||
@property(nonatomic, readonly) NSDictionary* query; // May be nil
|
|
||||||
@property(nonatomic, readonly) NSString* contentType; // Automatically parsed from headers (nil if request has no body or set to "application/octet-stream" if a body is present without a "Content-Type" header)
|
/**
|
||||||
@property(nonatomic, readonly) NSUInteger contentLength; // Automatically parsed from headers (NSNotFound if request has no "Content-Length" header)
|
* Returns the parsed and unescaped query component of the URL for the request.
|
||||||
@property(nonatomic, readonly) NSDate* ifModifiedSince; // Automatically parsed from headers (nil if request has no "If-Modified-Since" header or it is malformatted)
|
*
|
||||||
@property(nonatomic, readonly) NSString* ifNoneMatch; // Automatically parsed from headers (nil if request has no "If-None-Match" header)
|
* @warning This property will be nil if there is no query in the URL.
|
||||||
@property(nonatomic, readonly) NSRange byteRange; // Automatically parsed from headers ([NSNotFound, 0] if request has no "Range" header, [offset, length] for byte range from beginning or [NSNotFound, -length] from end)
|
*/
|
||||||
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding; // Automatically parsed from headers
|
@property(nonatomic, readonly) NSDictionary* query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content type for the body of the request (this property is
|
||||||
|
* automatically parsed from the HTTP headers).
|
||||||
|
*
|
||||||
|
* This property will be nil if the request has no body or set to
|
||||||
|
* "application/octet-stream" if a body is present but there was no
|
||||||
|
* "Content-Type" header.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSString* contentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the content length for the body of the request (this property is
|
||||||
|
* automatically parsed from the HTTP headers).
|
||||||
|
*
|
||||||
|
* This property will be set to "NSNotFound" if the request has no body or
|
||||||
|
* if there is a body but no "Content-Length" header, typically because
|
||||||
|
* chunked transfer encoding is used.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSUInteger contentLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parsed "If-Modified-Since" header or nil if absent of malformed.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSDate* ifModifiedSince;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parsed "If-None-Match" header or nil if absent of malformed.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSString* ifNoneMatch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the parsed "Range" header or (NSNotFound, 0) if absent or malformed.
|
||||||
|
* The range will be set to (offset, length) if expressed from the beginning
|
||||||
|
* of the body, or (NSNotFound, -length) if expressed from the end of the body.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) NSRange byteRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the client supports gzip content encoding (this property is
|
||||||
|
* automatically parsed from the HTTP headers).
|
||||||
|
*/
|
||||||
|
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is the designated initializer for the class.
|
||||||
|
*/
|
||||||
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query;
|
- (instancetype)initWithMethod:(NSString*)method url:(NSURL*)url headers:(NSDictionary*)headers path:(NSString*)path query:(NSDictionary*)query;
|
||||||
- (BOOL)hasBody; // Convenience method that checks if "contentType" is not nil
|
|
||||||
- (BOOL)hasByteRange; // Convenience method that checks "byteRange"
|
/**
|
||||||
|
* Convenience method that checks if the contentType property is defined.
|
||||||
|
*/
|
||||||
|
- (BOOL)hasBody;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that checks if the byteRange property is defined.
|
||||||
|
*/
|
||||||
|
- (BOOL)hasByteRange;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -27,29 +27,162 @@
|
|||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This protocol is used by the GCDWebServerConnection to communicate with
|
||||||
|
* the GCDWebServerResponse and read the sent HTTP body data.
|
||||||
|
*
|
||||||
|
* Note that multiple GCDWebServerBodyReader objects can be chained together
|
||||||
|
* internally e.g. to automatically apply gzip encoding to the content before
|
||||||
|
* passing it on to the GCDWebServerResponse.
|
||||||
|
*
|
||||||
|
* @warning These methods can be called on any GCD thread.
|
||||||
|
*/
|
||||||
@protocol GCDWebServerBodyReader <NSObject>
|
@protocol GCDWebServerBodyReader <NSObject>
|
||||||
- (BOOL)open:(NSError**)error; // Return NO on error ("error" is guaranteed to be non-NULL)
|
|
||||||
- (NSData*)readData:(NSError**)error; // Must return nil on error or empty NSData if at end ("error" is guaranteed to be non-NULL)
|
/**
|
||||||
|
* This method is called before any body data is sent.
|
||||||
|
*
|
||||||
|
* It should return YES on success or NO on failure and set the "error" argument
|
||||||
|
* which is guaranteed to be non-NULL.
|
||||||
|
*/
|
||||||
|
- (BOOL)open:(NSError**)error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called whenever body data is ready to be sent.
|
||||||
|
*
|
||||||
|
* It should return a non-empty NSData if there is body data available,
|
||||||
|
* or an empty NSData there is no more body data, or nil on error and set
|
||||||
|
* the "error" argument which is guaranteed to be non-NULL.
|
||||||
|
*/
|
||||||
|
- (NSData*)readData:(NSError**)error;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is called after all body data has been sent.
|
||||||
|
*/
|
||||||
- (void)close;
|
- (void)close;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The GCDWebServerResponse class is used to wrap a single HTTP response.
|
||||||
|
* It is instantiated by the handler of the GCDWebServer that handled the request.
|
||||||
|
* If a body is present, the methods from the GCDWebServerBodyReader protocol
|
||||||
|
* will be called by the GCDWebServerConnection to retrieve it.
|
||||||
|
*
|
||||||
|
* The default implementation of the GCDWebServerBodyReader protocol
|
||||||
|
* on the class simply returns an empty body.
|
||||||
|
*
|
||||||
|
* @warning GCDWebServerResponse instances can be created and used on any GCD thread.
|
||||||
|
*/
|
||||||
@interface GCDWebServerResponse : NSObject <GCDWebServerBodyReader>
|
@interface GCDWebServerResponse : NSObject <GCDWebServerBodyReader>
|
||||||
@property(nonatomic, copy) NSString* contentType; // Default is nil i.e. no body (must be set if a body is present)
|
|
||||||
@property(nonatomic) NSUInteger contentLength; // Default is NSNotFound i.e. undefined (if a body is present but length is undefined, chunked transfer encoding will be enabled)
|
/**
|
||||||
@property(nonatomic) NSInteger statusCode; // Default is 200
|
* Sets the content type for the body of the response.
|
||||||
@property(nonatomic) NSUInteger cacheControlMaxAge; // Default is 0 seconds i.e. "Cache-Control: no-cache"
|
* This property must be set if a body is present.
|
||||||
@property(nonatomic, retain) NSDate* lastModifiedDate; // Default is nil i.e. no "Last-Modified" header
|
*
|
||||||
@property(nonatomic, copy) NSString* eTag; // Default is nil i.e. no "ETag" header
|
* The default value is nil i.e. the response has no body.
|
||||||
@property(nonatomic, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled; // Default is disabled
|
*/
|
||||||
|
@property(nonatomic, copy) NSString* contentType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the content length for the body of the response. If a body is present
|
||||||
|
* but this property is set to "NSNotFound", this means the length of the body
|
||||||
|
* cannot be known ahead of time and chunked transfer encoding will be
|
||||||
|
* automatically enabled by the GCDWebServerConnection to comply with HTTP/1.1
|
||||||
|
* specifications.
|
||||||
|
*
|
||||||
|
* The default value is "NSNotFound" i.e. the response has no body or its length
|
||||||
|
* is undefined.
|
||||||
|
*/
|
||||||
|
@property(nonatomic) NSUInteger contentLength;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the HTTP status code for the response.
|
||||||
|
*
|
||||||
|
* The default value is 200 i.e. "OK".
|
||||||
|
*/
|
||||||
|
@property(nonatomic) NSInteger statusCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the caching hint for the response using the "Cache-Control" header.
|
||||||
|
* This value is expressed in seconds.
|
||||||
|
*
|
||||||
|
* The default value is 0 i.e. "no-cache".
|
||||||
|
*/
|
||||||
|
@property(nonatomic) NSUInteger cacheControlMaxAge;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the last modified date for the response using the "Last-Modified" header.
|
||||||
|
*
|
||||||
|
* The default value is nil.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, retain) NSDate* lastModifiedDate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ETag for the response using the "ETag" header.
|
||||||
|
*
|
||||||
|
* The default value is nil.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, copy) NSString* eTag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enables gzip encoding for the response body.
|
||||||
|
*
|
||||||
|
* The default value is NO.
|
||||||
|
*
|
||||||
|
* @warning Enabling gzip encoding will remove any "Content-Length" header
|
||||||
|
* since the length of the body is not known anymore. The client will still
|
||||||
|
* be able to determine the body length when connection is closed per
|
||||||
|
* HTTP/1.1 specifications.
|
||||||
|
*/
|
||||||
|
@property(nonatomic, getter=isGZipContentEncodingEnabled) BOOL gzipContentEncodingEnabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a default response.
|
||||||
|
*/
|
||||||
+ (instancetype)response;
|
+ (instancetype)response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is the designated initializer for the class.
|
||||||
|
*/
|
||||||
- (instancetype)init;
|
- (instancetype)init;
|
||||||
- (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header; // Pass nil value to remove header
|
|
||||||
- (BOOL)hasBody; // Convenience method that checks if "contentType" is not nil
|
/**
|
||||||
|
* Sets an additional HTTP header on the response.
|
||||||
|
* Pass a nil value to remove an additional header.
|
||||||
|
*
|
||||||
|
* @warning Do not attempt to override the primary headers used
|
||||||
|
* by GCDWebServerResponse e.g. "Content-Type" or "ETag".
|
||||||
|
*/
|
||||||
|
- (void)setValue:(NSString*)value forAdditionalHeader:(NSString*)header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method that checks if the contentType property is defined.
|
||||||
|
*/
|
||||||
|
- (BOOL)hasBody;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface GCDWebServerResponse (Extensions)
|
@interface GCDWebServerResponse (Extensions)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a default response with a specific HTTP status code.
|
||||||
|
*/
|
||||||
+ (instancetype)responseWithStatusCode:(NSInteger)statusCode;
|
+ (instancetype)responseWithStatusCode:(NSInteger)statusCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an HTTP redirect response to a new URL.
|
||||||
|
*/
|
||||||
+ (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
|
+ (instancetype)responseWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes a default response with a specific HTTP status code.
|
||||||
|
*/
|
||||||
- (instancetype)initWithStatusCode:(NSInteger)statusCode;
|
- (instancetype)initWithStatusCode:(NSInteger)statusCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes an HTTP redirect response to a new URL.
|
||||||
|
*/
|
||||||
- (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
|
- (instancetype)initWithRedirect:(NSURL*)location permanent:(BOOL)permanent;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
|
|
||||||
- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader {
|
- (id)initWithResponse:(GCDWebServerResponse*)response reader:(id<GCDWebServerBodyReader>)reader {
|
||||||
if ((self = [super initWithResponse:response reader:reader])) {
|
if ((self = [super initWithResponse:response reader:reader])) {
|
||||||
response.contentLength = NSNotFound; // Make sure "Content-Length" header is not set since we don't know it (client will determine body length when connection is closed)
|
response.contentLength = NSNotFound; // Make sure "Content-Length" header is not set since we don't know it
|
||||||
[response setValue:@"gzip" forAdditionalHeader:@"Content-Encoding"];
|
[response setValue:@"gzip" forAdditionalHeader:@"Content-Encoding"];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
Reference in New Issue
Block a user