1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
|
/** -*- objc -*-
*
* Author: Sergei Golovin <svgdev@mail.ru>
*
* TestWebServer is intended to be used in the tests where a web service is
* needed. The class's instance is instantiated with the method
* -[initWithAddress:port:mode:extra] and then started with the call -[start:].
* When started the TestWebServer starts in it's turn a SimpleWebServer instance
* in the same thread unless it is initialized with the argument 'mode' set to
* 'YES' to run it in a detached thread.
*
* It is designed to call the delegate's callbacks (if implemented) of
* the TestWebServerDelegate protocol for every request made to
* the SimpleWebServer's assigned address on the SimpleWebServer's assigned port
* (by default localhost and 1234 respectively). However it currently doesn't
* handle any request on it's own. Instead the class uses a collection of
* handlers. Every handler makes a custom response. So the TestWebServer only
* has to dispatch a request to a corresponding handler and then to send back
* the handler's response to the SimpleWebServer instance. See RequestHandler
* for more information.
*
* TestWebServer can be supplied with additional parameters via the argument
* 'extra' of the initializer -[initWithAddress:port:mode:extra].
* See that method's description for the currently supported key-value pairs.
*
* The pattern of use:
* ----------------------------------------------------------------------------
* NSDictionary *extra = [NSDictionary dictionaryWithObjectsAndKeys:
* @"https", @"Protocol",
* nil];
* TestWebServer *server = [[TestWebServer alloc] initWithAddress: @"localhost"
* port: @"1234"
* mode: NO
* extra: extra];
* ADelegateClass *del = [ADelegateClass new];
* [server setDelegate: del];
* [server start: extra];
* ....
* <runloop>
* ....
* [server stop];
* DESTROY(server);
* DESTROY(del);
* ----------------------------------------------------------------------------
*
*
* The TestWebServer can response to the following resource paths:
*
* /index
* displays the page with all supported resources
* /withoutauth/
* if it is a part of the request's URL then the TestWebServer
* will NOT check authentication/authorization of the client.
*
* /204/
* /301/
* /400/
* /401/
* /402/
* /404/
* /405/
* /409/
* /500/
* /505/
* /507/
* a try to access to this resources will lead the TestWebServer
* to produce one of the pre-defined responses with the status code
* is equal to the corresponding number.
* The pre-defined responses are:
* 204 "" (empty string)
* 301 "Redirect to <URL>"
* Returns in the header 'Location' a new <URL> which by default
* has the same protocol, address but the port is incremented by
* 1 (e.g. http://localhost:1235/ with other parameters set to
* their default values).
* 400 "You have issued a request with invalid data"
* 401 "Invalid login or password"
* 403 "Check your balance"
* 404 "The resource you are trying to access is not found"
* 405 "You can't do that"
* 409 "The resource you are trying to access is busy"
* 500 "System error"
* 505 "There is network protocol inconsistency"
* 507 "Insufficient storage"
*
* If you want more verbosity call the method -[setDebug: YES].
*
*/
#import "SimpleWebServer.h"
#import <Foundation/Foundation.h>
@class RequestHandler;
@interface TestWebServer : NSObject <SimpleWebServerDelegate>
{
/* the debug mode flag */
BOOL _debug;
/* the IP address to attach to... see DEFAULTADDRESS at the beginning
* of the implementaion */
NSString *_address;
/* the port to listen on... see DEFAULTPORT in the beginning
* of the implementaion */
NSString *_port;
/* whether the TestWebServer listens for HTTPS requests */
BOOL _isSecure;
/* the login for basic authentication */
NSString *_login;
/* the password for basic authentication */
NSString *_password;
/* holds the extra argument which is for a future use...
* Currently it is expected to be a dictionary with predetermined
* keys ( see the description of -[initWithAddress:port:mode:extra:]) */
id _extra;
/* the flag used as a trigger to stop the detached thread */
BOOL _threadToQuit;
/* holds the SimpleWebServer accepting incoming connections */
SimpleWebServer *_server;
/* holds the detached thread the SimpleWebServer is running on...
* nil if it runs in the same thread as the calling code */
NSThread *_serverThread;
/* the delegate ... NOT RETAINED...
* see below the protocol TestWebServerDelegate */
id _delegate;
/* the lock used for synchronization between threads mainly
* to wait for the SimpleWebServer is started/stopped...
* the condition list:
* READY - the initial condition
* STARTED - the SimpleWebServer has been started;
* STOPPED - the SimpleWebServer has been stopped;
*/
NSConditionLock *_lock;
/* the traversal map used to pick a right handler from the request's path */
NSMutableDictionary *_traversalMap;
}
/**
* Initializes the intance with default parameters.
*/
- (id)init;
/**
* Initializes an instance with it's SimpleWebServer accepting connection on
* the specified address and port. The mode decides whether to run
* the SimpleWebServer on the detached thread (NO means it won't be detached).
* The argument extra is for future enhancement and could be of the class
* NSDictionary whose key-value pairs set various parameters.
* The current code supports the following extra keys:
* 'Login' - the login for basic authentication
* 'Password' - the password for basic authentication
* 'Protocol' - 'http' means waiting for HTTP requests
* 'https' - for HTTPS requests
*/
- (id)initWithAddress:(NSString *)address
port:(NSString *)port
mode:(BOOL)detached
extra:(id)extra;
- (void)dealloc;
/**
* Starts the SimpleWebServer accepting incoming connections.
* The supplied argument is for future enhancement and currently has no meaning.
* It isn't retained by the method.
*/
- (void)start:(id)extra;
/**
* Stops the SimpleWebServer. The instance ceases to accept incoming connections.
*/
- (void)stop;
/* SimpleWebServerDelegate */
/**
* The main job of request-response cycle is done here. The method is called
* when all request's bytes are read. It must be supplied with the incoming
* request and the response document which is about to be sent back to the web
* client. The handling code within the method would change the supplied response.
*/
- (BOOL) processRequest:(GSMimeDocument *)request
response:(GSMimeDocument *)response
for:(SimpleWebServer *)server;
/* end of SimpleWebServerDelegate */
/* getters */
/**
* Returns the address which SimpleWebServer is bound to.
*/
- (NSString *)address;
/**
* Returns the port which the SimpleWebServer listens on.
*/
- (NSString *)port;
/**
* Returns the login for basic authentication.
*/
- (NSString *)login;
/**
* Returns the password for basic authentication.
*/
- (NSString *)password;
/**
* Returns YES if the instance waits for HTTPS requests.
*/
- (BOOL)isSecure;
/* end of getters */
/* setters */
/**
* Sets the delegate implementing TestWebServerDelegate protocol.
* The argument isn't retained by the method.
*/
- (void)setDelegate:(id)delegate;
/**
* Sets the debug mode (more verbose).
*/
- (void)setDebug:(BOOL)mode;
/* end of setters */
@end /* TestWebServer */
/**
* The protocol's methods are called during processing of a request.
*/
@protocol TestWebServerDelegate
/**
* Called by the handler when it has got the supplied request
* from the supplied TestWebServer instance.
*/
- (void)handler:(id)handler
gotRequest:(GSMimeDocument *)request
with:(TestWebServer *)server;
/**
* Called by the handler when it is going to send the response
* on an unauthorized request (an invalid request or no credentials are supplied)
* via the supplied TestWebServer.
*/
- (void)handler:(id)handler
willSendUnauthorized:(GSMimeDocument *)response
with:(TestWebServer *)server;
/**
* Called by the handler when it has got the supplied request
* with valid credentials from the supplied TestWebServer instance.
*/
- (void)handler:(id)handler
gotAuthorized:(GSMimeDocument *)request
with:(TestWebServer *)server;
/**
* Called by the handler when it is going to send the response
* on any request except an unauthorized one via the supplied TestWebServer.
*/
- (void)handler:(id)handler
willSend:(GSMimeDocument *)response
with:(TestWebServer *)server;
/**
* Called when the timeout is exceeded.
*/
- (void)timeoutExceededByHandler:(id)handler;
@end /* TestWebServerDelegate */
|