iCuke 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +13 -0
- data/LICENSE +20 -0
- data/README.rdoc +69 -0
- data/Rakefile +80 -0
- data/VERSION +1 -0
- data/app/iCuke/.gitignore +1 -0
- data/app/iCuke/Classes/FlipsideView.h +13 -0
- data/app/iCuke/Classes/FlipsideView.m +32 -0
- data/app/iCuke/Classes/FlipsideViewController.h +25 -0
- data/app/iCuke/Classes/FlipsideViewController.m +54 -0
- data/app/iCuke/Classes/MainView.h +15 -0
- data/app/iCuke/Classes/MainView.m +32 -0
- data/app/iCuke/Classes/MainViewController.h +16 -0
- data/app/iCuke/Classes/MainViewController.m +86 -0
- data/app/iCuke/Classes/iCukeAppDelegate.h +20 -0
- data/app/iCuke/Classes/iCukeAppDelegate.m +33 -0
- data/app/iCuke/FlipsideView.xib +444 -0
- data/app/iCuke/MainView.xib +520 -0
- data/app/iCuke/MainWindow.xib +355 -0
- data/app/iCuke/SniffingView.h +20 -0
- data/app/iCuke/SniffingView.m +191 -0
- data/app/iCuke/iCuke-Info.plist +30 -0
- data/app/iCuke/iCuke.xcodeproj/project.pbxproj +313 -0
- data/app/iCuke/iCuke_Prefix.pch +14 -0
- data/app/iCuke/main.m +16 -0
- data/ext/iCuke/.gitignore +2 -0
- data/ext/iCuke/DefaultsResponse.h +5 -0
- data/ext/iCuke/DefaultsResponse.m +67 -0
- data/ext/iCuke/EventResponse.h +5 -0
- data/ext/iCuke/EventResponse.m +122 -0
- data/ext/iCuke/Rakefile +22 -0
- data/ext/iCuke/Recorder.h +15 -0
- data/ext/iCuke/Recorder.m +85 -0
- data/ext/iCuke/RecorderResponse.h +5 -0
- data/ext/iCuke/RecorderResponse.m +59 -0
- data/ext/iCuke/SynthesizeSingleton.h +68 -0
- data/ext/iCuke/ViewResponse.h +5 -0
- data/ext/iCuke/ViewResponse.m +84 -0
- data/ext/iCuke/Viewer.h +8 -0
- data/ext/iCuke/Viewer.m +153 -0
- data/ext/iCuke/iCukeHTTPResponseHandler.h +50 -0
- data/ext/iCuke/iCukeHTTPResponseHandler.m +381 -0
- data/ext/iCuke/iCukeHTTPServer.h +53 -0
- data/ext/iCuke/iCukeHTTPServer.m +365 -0
- data/ext/iCuke/iCukeServer.h +16 -0
- data/ext/iCuke/iCukeServer.m +46 -0
- data/ext/iCuke/json/JSON.h +50 -0
- data/ext/iCuke/json/NSObject+SBJSON.h +68 -0
- data/ext/iCuke/json/NSObject+SBJSON.m +53 -0
- data/ext/iCuke/json/NSString+SBJSON.h +58 -0
- data/ext/iCuke/json/NSString+SBJSON.m +55 -0
- data/ext/iCuke/json/SBJSON.h +75 -0
- data/ext/iCuke/json/SBJSON.m +212 -0
- data/ext/iCuke/json/SBJsonBase.h +86 -0
- data/ext/iCuke/json/SBJsonBase.m +78 -0
- data/ext/iCuke/json/SBJsonParser.h +87 -0
- data/ext/iCuke/json/SBJsonParser.m +475 -0
- data/ext/iCuke/json/SBJsonWriter.h +129 -0
- data/ext/iCuke/json/SBJsonWriter.m +228 -0
- data/features/icuke.feature +17 -0
- data/features/support/env.rb +3 -0
- data/iCuke.gemspec +113 -0
- data/lib/icuke/cucumber.rb +211 -0
- data/lib/icuke/simulate.rb +132 -0
- data/lib/icuke/simulator.rb +107 -0
- data/lib/icuke.rb +1 -0
- metadata +163 -0
@@ -0,0 +1,381 @@
|
|
1
|
+
//
|
2
|
+
// HTTPResponseHandler.m
|
3
|
+
// TextTransfer
|
4
|
+
//
|
5
|
+
// Created by Matt Gallagher on 2009/07/13.
|
6
|
+
// Copyright 2009 Matt Gallagher. All rights reserved.
|
7
|
+
//
|
8
|
+
// Permission is given to use this source code file, free of charge, in any
|
9
|
+
// project, commercial or otherwise, entirely at your risk, with the condition
|
10
|
+
// that any redistribution (in part or whole) of source code must retain
|
11
|
+
// this copyright and permission notice. Attribution in compiled projects is
|
12
|
+
// appreciated but not required.
|
13
|
+
//
|
14
|
+
|
15
|
+
#import "iCukeHTTPResponseHandler.h"
|
16
|
+
#import "iCukeHTTPServer.h"
|
17
|
+
#import "ViewResponse.h"
|
18
|
+
|
19
|
+
@implementation iCukeHTTPResponseHandler
|
20
|
+
|
21
|
+
static NSMutableArray *registeredHandlers = nil;
|
22
|
+
|
23
|
+
//
|
24
|
+
// priority
|
25
|
+
//
|
26
|
+
// The priority determines which request handlers are given the option to
|
27
|
+
// handle a request first. The highest number goes first, with the base class
|
28
|
+
// (HTTPResponseHandler) implementing a 501 error response at priority 0
|
29
|
+
// (the lowest priorty).
|
30
|
+
//
|
31
|
+
// Even if subclasses have a 0 priority, they will always receive precedence
|
32
|
+
// over the base class, since the base class' implementation is intended as
|
33
|
+
// an error condition only.
|
34
|
+
//
|
35
|
+
// returns the priority.
|
36
|
+
//
|
37
|
+
+ (NSUInteger)priority
|
38
|
+
{
|
39
|
+
return 0;
|
40
|
+
}
|
41
|
+
|
42
|
+
//
|
43
|
+
// load
|
44
|
+
//
|
45
|
+
// Implementing the load method and invoking
|
46
|
+
// [HTTPResponseHandler registerHandler:self] causes HTTPResponseHandler
|
47
|
+
// to register this class in the list of registered HTTP response handlers.
|
48
|
+
//
|
49
|
+
+ (void)load
|
50
|
+
{
|
51
|
+
[iCukeHTTPResponseHandler registerHandler:self];
|
52
|
+
}
|
53
|
+
|
54
|
+
//
|
55
|
+
// registerHandler:
|
56
|
+
//
|
57
|
+
// Inserts the HTTPResponseHandler class into the priority list.
|
58
|
+
//
|
59
|
+
+ (void)registerHandler:(Class)handlerClass
|
60
|
+
{
|
61
|
+
if (registeredHandlers == nil)
|
62
|
+
{
|
63
|
+
registeredHandlers = [[NSMutableArray alloc] init];
|
64
|
+
}
|
65
|
+
|
66
|
+
NSUInteger i;
|
67
|
+
NSUInteger count = [registeredHandlers count];
|
68
|
+
for (i = 0; i < count; i++)
|
69
|
+
{
|
70
|
+
if ([handlerClass priority] >= [[registeredHandlers objectAtIndex:i] priority])
|
71
|
+
{
|
72
|
+
break;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
[registeredHandlers insertObject:handlerClass atIndex:i];
|
76
|
+
}
|
77
|
+
|
78
|
+
//
|
79
|
+
// canHandleRequest:method:url:headerFields:
|
80
|
+
//
|
81
|
+
// Class method to determine if the response handler class can handle
|
82
|
+
// a given request.
|
83
|
+
//
|
84
|
+
// Parameters:
|
85
|
+
// aRequest - the request
|
86
|
+
// requestMethod - the request method
|
87
|
+
// requestURL - the request URL
|
88
|
+
// requestHeaderFields - the request headers
|
89
|
+
//
|
90
|
+
// returns YES (if the handler can handle the request), NO (otherwise)
|
91
|
+
//
|
92
|
+
+ (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest
|
93
|
+
method:(NSString *)requestMethod
|
94
|
+
url:(NSURL *)requestURL
|
95
|
+
headerFields:(NSDictionary *)requestHeaderFields
|
96
|
+
{
|
97
|
+
return YES;
|
98
|
+
}
|
99
|
+
|
100
|
+
//
|
101
|
+
// handlerClassForRequest:method:url:headerFields:
|
102
|
+
//
|
103
|
+
// Important method to edit for your application.
|
104
|
+
//
|
105
|
+
// This method determines (from the HTTP request message, URL and headers)
|
106
|
+
// which
|
107
|
+
//
|
108
|
+
// Parameters:
|
109
|
+
// aRequest - the CFHTTPMessageRef, with data at least as far as the end
|
110
|
+
// of the headers
|
111
|
+
// requestMethod - the request method (GET, POST, PUT, DELETE etc)
|
112
|
+
// requestURL - the URL (likely only contains a path)
|
113
|
+
// requestHeaderFields - the parsed header fields
|
114
|
+
//
|
115
|
+
// returns the class to handle the request, or nil if no handler exists.
|
116
|
+
//
|
117
|
+
+ (Class)handlerClassForRequest:(CFHTTPMessageRef)aRequest
|
118
|
+
method:(NSString *)requestMethod
|
119
|
+
url:(NSURL *)requestURL
|
120
|
+
headerFields:(NSDictionary *)requestHeaderFields
|
121
|
+
{
|
122
|
+
for (Class handlerClass in registeredHandlers)
|
123
|
+
{
|
124
|
+
if ([handlerClass canHandleRequest:aRequest
|
125
|
+
method:requestMethod
|
126
|
+
url:requestURL
|
127
|
+
headerFields:requestHeaderFields])
|
128
|
+
{
|
129
|
+
return handlerClass;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
return nil;
|
134
|
+
}
|
135
|
+
|
136
|
+
//
|
137
|
+
// handleRequest:fileHandle:server:
|
138
|
+
//
|
139
|
+
// This method parses the request method and header components, invokes
|
140
|
+
// +[handlerClassForRequest:method:url:headerFields:] to determine a handler
|
141
|
+
// class (if any) and creates the handler.
|
142
|
+
//
|
143
|
+
// Parameters:
|
144
|
+
// aRequest - the CFHTTPMessageRef request requiring a response
|
145
|
+
// requestFileHandle - the file handle for the incoming request (still
|
146
|
+
// open and possibly receiving data) and for the outgoing response
|
147
|
+
// aServer - the server that is invoking us
|
148
|
+
//
|
149
|
+
// returns the initialized handler (if one can handle the request) or nil
|
150
|
+
// (if no valid handler exists).
|
151
|
+
//
|
152
|
+
+ (iCukeHTTPResponseHandler *)handlerForRequest:(CFHTTPMessageRef)aRequest
|
153
|
+
fileHandle:(NSFileHandle *)requestFileHandle
|
154
|
+
server:(iCukeHTTPServer *)aServer
|
155
|
+
{
|
156
|
+
NSDictionary *requestHeaderFields =
|
157
|
+
[(NSDictionary *)CFHTTPMessageCopyAllHeaderFields(aRequest)
|
158
|
+
autorelease];
|
159
|
+
NSURL *requestURL =
|
160
|
+
[(NSURL *)CFHTTPMessageCopyRequestURL(aRequest) autorelease];
|
161
|
+
NSString *method =
|
162
|
+
[(NSString *)CFHTTPMessageCopyRequestMethod(aRequest)
|
163
|
+
autorelease];
|
164
|
+
|
165
|
+
Class classForRequest =
|
166
|
+
[self handlerClassForRequest:aRequest
|
167
|
+
method:method
|
168
|
+
url:requestURL
|
169
|
+
headerFields:requestHeaderFields];
|
170
|
+
|
171
|
+
iCukeHTTPResponseHandler *handler =
|
172
|
+
[[[classForRequest alloc]
|
173
|
+
initWithRequest:aRequest
|
174
|
+
method:method
|
175
|
+
url:requestURL
|
176
|
+
headerFields:requestHeaderFields
|
177
|
+
fileHandle:requestFileHandle
|
178
|
+
server:aServer]
|
179
|
+
autorelease];
|
180
|
+
|
181
|
+
return handler;
|
182
|
+
}
|
183
|
+
|
184
|
+
//
|
185
|
+
// initWithRequest:method:url:headerFields:fileHandle:server:
|
186
|
+
//
|
187
|
+
// Init method for the handler. This method is mostly just a value copy operation
|
188
|
+
// so that the parts of the request don't need to be reparsed.
|
189
|
+
//
|
190
|
+
// Parameters:
|
191
|
+
// aRequest - the CFHTTPMessageRef
|
192
|
+
// method - the request method
|
193
|
+
// requestURL - the URL
|
194
|
+
// requestHeaderFields - the CFHTTPMessageRef header fields
|
195
|
+
// requestFileHandle - the incoming request file handle, also used for
|
196
|
+
// the outgoing response.
|
197
|
+
// aServer - the server that spawned us
|
198
|
+
//
|
199
|
+
// returns the initialized object
|
200
|
+
//
|
201
|
+
- (id)initWithRequest:(CFHTTPMessageRef)aRequest
|
202
|
+
method:(NSString *)method
|
203
|
+
url:(NSURL *)requestURL
|
204
|
+
headerFields:(NSDictionary *)requestHeaderFields
|
205
|
+
fileHandle:(NSFileHandle *)requestFileHandle
|
206
|
+
server:(iCukeHTTPServer *)aServer
|
207
|
+
{
|
208
|
+
self = [super init];
|
209
|
+
if (self != nil)
|
210
|
+
{
|
211
|
+
request = (CFHTTPMessageRef)[(id)aRequest retain];
|
212
|
+
requestMethod = [method retain];
|
213
|
+
url = [requestURL retain];
|
214
|
+
headerFields = [requestHeaderFields retain];
|
215
|
+
fileHandle = [requestFileHandle retain];
|
216
|
+
server = [aServer retain];
|
217
|
+
|
218
|
+
[[NSNotificationCenter defaultCenter]
|
219
|
+
addObserver:self
|
220
|
+
selector:@selector(receiveIncomingDataNotification:)
|
221
|
+
name:NSFileHandleDataAvailableNotification
|
222
|
+
object:fileHandle];
|
223
|
+
|
224
|
+
[fileHandle waitForDataInBackgroundAndNotify];
|
225
|
+
}
|
226
|
+
return self;
|
227
|
+
}
|
228
|
+
|
229
|
+
//
|
230
|
+
// startResponse
|
231
|
+
//
|
232
|
+
// Begin sending a response over the fileHandle. Trivial cases can
|
233
|
+
// synchronously return a response but everything else should spawn a thread
|
234
|
+
// or otherwise asynchronously start returning the response data.
|
235
|
+
//
|
236
|
+
// THIS IS THE PRIMARY METHOD FOR SUBCLASSES TO OVERRIDE. YOU DO NOT NEED
|
237
|
+
// TO INVOKE SUPER FOR THIS METHOD.
|
238
|
+
//
|
239
|
+
// This method should only be invoked from HTTPServer (it needs to add the
|
240
|
+
// object to its responseHandlers before this method is invoked).
|
241
|
+
//
|
242
|
+
// [server closeHandler:self] should be invoked when done sending data.
|
243
|
+
//
|
244
|
+
- (void)startResponse
|
245
|
+
{
|
246
|
+
CFHTTPMessageRef response =
|
247
|
+
CFHTTPMessageCreateResponse(
|
248
|
+
kCFAllocatorDefault, 501, NULL, kCFHTTPVersion1_1);
|
249
|
+
CFHTTPMessageSetHeaderFieldValue(
|
250
|
+
response, (CFStringRef)@"Content-Type", (CFStringRef)@"text/plain");
|
251
|
+
CFHTTPMessageSetHeaderFieldValue(
|
252
|
+
response, (CFStringRef)@"Connection", (CFStringRef)@"close");
|
253
|
+
CFHTTPMessageSetBody(
|
254
|
+
response,
|
255
|
+
(CFDataRef)[[NSString stringWithFormat:
|
256
|
+
@"No handler exists to handle %@.",
|
257
|
+
[url absoluteString]]
|
258
|
+
dataUsingEncoding:NSUTF8StringEncoding]);
|
259
|
+
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
|
260
|
+
@try
|
261
|
+
{
|
262
|
+
[fileHandle writeData:(NSData *)headerData];
|
263
|
+
}
|
264
|
+
@catch (NSException *exception)
|
265
|
+
{
|
266
|
+
// Ignore the exception, it normally just means the client
|
267
|
+
// closed the connection from the other end.
|
268
|
+
}
|
269
|
+
@finally
|
270
|
+
{
|
271
|
+
CFRelease(headerData);
|
272
|
+
CFRelease(response);
|
273
|
+
[server closeHandler:self];
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
//
|
278
|
+
// endResponse
|
279
|
+
//
|
280
|
+
// Closes the outgoing file handle.
|
281
|
+
//
|
282
|
+
// You should not invoke this method directly. It should only be invoked from
|
283
|
+
// HTTPServer (it needs to remove the object from its responseHandlers before
|
284
|
+
// this method is invoked). To close a reponse handler, use
|
285
|
+
// [server closeHandler:responseHandler].
|
286
|
+
//
|
287
|
+
// Subclasses should stop any other activity when this method is invoked and
|
288
|
+
// invoke super to close the file handle.
|
289
|
+
//
|
290
|
+
// If the connection is persistent, you must set fileHandle to nil (without
|
291
|
+
// closing the file) to prevent the connection getting closed by this method.
|
292
|
+
//
|
293
|
+
- (void)endResponse
|
294
|
+
{
|
295
|
+
if (fileHandle)
|
296
|
+
{
|
297
|
+
[[NSNotificationCenter defaultCenter]
|
298
|
+
removeObserver:self
|
299
|
+
name:NSFileHandleDataAvailableNotification
|
300
|
+
object:fileHandle];
|
301
|
+
[fileHandle closeFile];
|
302
|
+
[fileHandle release];
|
303
|
+
fileHandle = nil;
|
304
|
+
}
|
305
|
+
|
306
|
+
[server release];
|
307
|
+
server = nil;
|
308
|
+
}
|
309
|
+
|
310
|
+
//
|
311
|
+
// receiveIncomingDataNotification:
|
312
|
+
//
|
313
|
+
// Continues to receive incoming data for the connection. Remember that the
|
314
|
+
// first data past the end of the headers may already have been read into
|
315
|
+
// the request.
|
316
|
+
//
|
317
|
+
// Override this method to read the complete HTTP Request Body. This is a
|
318
|
+
// complicated process if you want to handle both Content-Length and all common
|
319
|
+
// Transfer-Encodings, so I haven't implemented it.
|
320
|
+
//
|
321
|
+
// If you want to handle persistent connections, you would need careful handling
|
322
|
+
// to determine the end of the request, seek the fileHandle so it points
|
323
|
+
// to the byte immediately after then end of this request, and then send an
|
324
|
+
// NSFileHandleConnectionAcceptedNotification notification with the fileHandle
|
325
|
+
// as the NSFileHandleNotificationFileHandleItem in the userInfo dictionary
|
326
|
+
// back to the server to handle the fileHandle as a new incoming request again
|
327
|
+
// (before setting fileHandle to nil so the connection won't get closed when this
|
328
|
+
// handler ends).
|
329
|
+
//
|
330
|
+
// Parameters:
|
331
|
+
// notification - notification that more data is available
|
332
|
+
//
|
333
|
+
- (void)receiveIncomingDataNotification:(NSNotification *)notification
|
334
|
+
{
|
335
|
+
NSFileHandle *incomingFileHandle = [notification object];
|
336
|
+
NSData *data = [incomingFileHandle availableData];
|
337
|
+
|
338
|
+
if ([data length] == 0)
|
339
|
+
{
|
340
|
+
[server closeHandler:self];
|
341
|
+
}
|
342
|
+
|
343
|
+
//
|
344
|
+
// This is a default implementation and simply ignores all data.
|
345
|
+
// If you need the HTTP body, you need to override this method to continue
|
346
|
+
// accumulating data. Don't forget that new data may need to be combined
|
347
|
+
// with any HTTP body data that may have already been received in the
|
348
|
+
// "request" body.
|
349
|
+
//
|
350
|
+
|
351
|
+
[incomingFileHandle waitForDataInBackgroundAndNotify];
|
352
|
+
}
|
353
|
+
|
354
|
+
//
|
355
|
+
// dealloc
|
356
|
+
//
|
357
|
+
// Stops the response if still running.
|
358
|
+
//
|
359
|
+
- (void)dealloc
|
360
|
+
{
|
361
|
+
if (server)
|
362
|
+
{
|
363
|
+
[self endResponse];
|
364
|
+
}
|
365
|
+
|
366
|
+
[(id)request release];
|
367
|
+
request = nil;
|
368
|
+
|
369
|
+
[requestMethod release];
|
370
|
+
requestMethod = nil;
|
371
|
+
|
372
|
+
[url release];
|
373
|
+
url = nil;
|
374
|
+
|
375
|
+
[headerFields release];
|
376
|
+
headerFields = nil;
|
377
|
+
|
378
|
+
[super dealloc];
|
379
|
+
}
|
380
|
+
|
381
|
+
@end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
//
|
2
|
+
// HTTPServer.h
|
3
|
+
// TextTransfer
|
4
|
+
//
|
5
|
+
// Created by Matt Gallagher on 2009/07/13.
|
6
|
+
// Copyright 2009 Matt Gallagher. All rights reserved.
|
7
|
+
//
|
8
|
+
// Permission is given to use this source code file, free of charge, in any
|
9
|
+
// project, commercial or otherwise, entirely at your risk, with the condition
|
10
|
+
// that any redistribution (in part or whole) of source code must retain
|
11
|
+
// this copyright and permission notice. Attribution in compiled projects is
|
12
|
+
// appreciated but not required.
|
13
|
+
//
|
14
|
+
|
15
|
+
#if TARGET_OS_IPHONE
|
16
|
+
#import <UIKit/UIKit.h>
|
17
|
+
#else
|
18
|
+
#import <Cocoa/Cocoa.h>
|
19
|
+
#endif
|
20
|
+
|
21
|
+
typedef enum
|
22
|
+
{
|
23
|
+
SERVER_STATE_IDLE,
|
24
|
+
SERVER_STATE_STARTING,
|
25
|
+
SERVER_STATE_RUNNING,
|
26
|
+
SERVER_STATE_STOPPING
|
27
|
+
} iCukeHTTPServerState;
|
28
|
+
|
29
|
+
@class iCukeHTTPResponseHandler;
|
30
|
+
|
31
|
+
@interface iCukeHTTPServer : NSObject
|
32
|
+
{
|
33
|
+
NSError *lastError;
|
34
|
+
NSFileHandle *listeningHandle;
|
35
|
+
CFSocketRef socket;
|
36
|
+
iCukeHTTPServerState state;
|
37
|
+
CFMutableDictionaryRef incomingRequests;
|
38
|
+
NSMutableSet *responseHandlers;
|
39
|
+
}
|
40
|
+
|
41
|
+
@property (nonatomic, readonly, retain) NSError *lastError;
|
42
|
+
@property (readonly, assign) iCukeHTTPServerState state;
|
43
|
+
|
44
|
+
+ (iCukeHTTPServer *)sharediCukeHTTPServer;
|
45
|
+
|
46
|
+
- (void)start;
|
47
|
+
- (void)stop;
|
48
|
+
|
49
|
+
- (void)closeHandler:(iCukeHTTPResponseHandler *)aHandler;
|
50
|
+
|
51
|
+
@end
|
52
|
+
|
53
|
+
extern NSString * const iCukeHTTPServerNotificationStateChanged;
|