iCuke 0.6.3 → 0.6.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +1 -1
- data/Gemfile +12 -0
- data/Gemfile.lock +41 -0
- data/README.markdown +126 -0
- data/Rakefile +34 -12
- data/VERSION +1 -1
- data/bin/icuke +12 -10
- data/ext/Rakefile +6 -0
- data/ext/iCuke/{sdk3.1/DefaultsResponse.h → DefaultsResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/DefaultsResponse.m → DefaultsResponse.m} +0 -0
- data/ext/iCuke/{sdk3.1/EventResponse.h → EventResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/EventResponse.m → EventResponse.m} +0 -0
- data/ext/iCuke/{sdk3.1/ModuleResponse.h → ModuleResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/ModuleResponse.m → ModuleResponse.m} +0 -0
- data/ext/iCuke/{sdk3.1/QuitResponse.h → QuitResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/QuitResponse.m → QuitResponse.m} +0 -0
- data/ext/iCuke/Rakefile +14 -13
- data/ext/iCuke/{sdk3.1/Recorder.h → Recorder.h} +0 -0
- data/ext/iCuke/{sdk3.1/Recorder.m → Recorder.m} +0 -0
- data/ext/iCuke/{sdk3.1/RecorderResponse.h → RecorderResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/RecorderResponse.m → RecorderResponse.m} +0 -0
- data/ext/iCuke/{sdk3.1/SynthesizeSingleton.h → SynthesizeSingleton.h} +0 -0
- data/ext/iCuke/{sdk3.1/ViewResponse.h → ViewResponse.h} +0 -0
- data/ext/iCuke/{sdk3.1/ViewResponse.m → ViewResponse.m} +0 -0
- data/ext/iCuke/{sdk3.1/Viewer.h → Viewer.h} +0 -0
- data/ext/iCuke/{sdk4.0/Viewer.m → Viewer.m} +0 -0
- data/ext/iCuke/{sdk3.1/iCukeHTTPResponseHandler.h → iCukeHTTPResponseHandler.h} +0 -0
- data/ext/iCuke/{sdk3.1/iCukeHTTPResponseHandler.m → iCukeHTTPResponseHandler.m} +0 -0
- data/ext/iCuke/{sdk3.1/iCukeHTTPServer.h → iCukeHTTPServer.h} +0 -0
- data/ext/iCuke/{sdk4.0/iCukeHTTPServer.m → iCukeHTTPServer.m} +4 -2
- data/ext/iCuke/{sdk3.1/iCukeServer.h → iCukeServer.h} +0 -0
- data/ext/iCuke/{sdk3.1/iCukeServer.m → iCukeServer.m} +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/JSON.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/NSObject+SBJSON.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/NSObject+SBJSON.m +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/NSString+SBJSON.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/NSString+SBJSON.m +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJSON.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJSON.m +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonBase.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonBase.m +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonParser.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonParser.m +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonWriter.h +0 -0
- data/ext/iCuke/{sdk3.1/json → json}/SBJsonWriter.m +0 -0
- data/features/starting_project.feature +18 -0
- data/features/step_definitions/shell.rb +41 -0
- data/features/support/env.rb +2 -0
- data/features/support/environment.rb +40 -0
- data/features/supported_sdks.feature +12 -0
- data/iCuke.gemspec +149 -161
- data/lib/icuke/configuration.rb +19 -0
- data/lib/icuke/core_ext.rb +27 -0
- data/lib/icuke/cucumber.rb +29 -265
- data/lib/icuke/cucumber_compat.rb +4 -0
- data/lib/icuke/icuke_world.rb +149 -0
- data/lib/icuke/sdk.rb +5 -13
- data/lib/icuke/simulator_driver.rb +201 -0
- data/lib/icuke/waxsim.rb +47 -9
- data/spec/cucumber_spec.rb +130 -0
- data/spec/fixtures/controls_page.xml +252 -0
- data/spec/process_spec.rb +76 -0
- data/spec/screen_spec.rb +173 -0
- data/spec/simulate_spec.rb +75 -0
- data/spec/simulator_spec.rb +28 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +67 -0
- metadata +222 -121
- data/.gitignore +0 -15
- data/README.rdoc +0 -68
- data/ext/WaxSim/Simulator.h +0 -31
- data/ext/WaxSim/Simulator.m +0 -131
- data/ext/WaxSim/WaxSim.m +0 -110
- data/ext/WaxSim/WaxSim.xcodeproj/project.pbxproj +0 -238
- data/ext/WaxSim/WaxSim_Prefix.pch +0 -7
- data/ext/WaxSim/build/Release/waxsim +0 -0
- data/ext/WaxSim/build/Release/waxsim.dSYM/Contents/Info.plist +0 -20
- data/ext/WaxSim/build/Release/waxsim.dSYM/Contents/Resources/DWARF/waxsim +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/Objects-normal/x86_64/Simulator.o +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/Objects-normal/x86_64/WaxSim.o +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/Objects-normal/x86_64/waxsim.LinkFileList +0 -2
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/WaxSim.dep +0 -6
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/WaxSim~.dep +0 -6
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/build-state.dat +0 -227
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/build-state~.dat +0 -227
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/waxsim-all-target-headers.hmap +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/waxsim-generated-files.hmap +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/waxsim-own-target-headers.hmap +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/waxsim-project-headers.hmap +0 -0
- data/ext/WaxSim/build/WaxSim.build/Release/WaxSim.build/waxsim.hmap +0 -0
- data/ext/WaxSim/iPhoneSimulatorRemoteClient/iPhoneSimulatorRemoteClient.h +0 -126
- data/ext/iCuke/sdk3.1/Rakefile +0 -20
- data/ext/iCuke/sdk3.1/Viewer.m +0 -203
- data/ext/iCuke/sdk3.1/iCukeHTTPServer.m +0 -365
- data/ext/iCuke/sdk4.0/DefaultsResponse.h +0 -5
- data/ext/iCuke/sdk4.0/DefaultsResponse.m +0 -66
- data/ext/iCuke/sdk4.0/EventResponse.h +0 -5
- data/ext/iCuke/sdk4.0/EventResponse.m +0 -130
- data/ext/iCuke/sdk4.0/ModuleResponse.h +0 -5
- data/ext/iCuke/sdk4.0/ModuleResponse.m +0 -76
- data/ext/iCuke/sdk4.0/QuitResponse.h +0 -5
- data/ext/iCuke/sdk4.0/QuitResponse.m +0 -23
- data/ext/iCuke/sdk4.0/Rakefile +0 -20
- data/ext/iCuke/sdk4.0/Recorder.h +0 -17
- data/ext/iCuke/sdk4.0/Recorder.m +0 -90
- data/ext/iCuke/sdk4.0/RecorderResponse.h +0 -6
- data/ext/iCuke/sdk4.0/RecorderResponse.m +0 -68
- data/ext/iCuke/sdk4.0/SynthesizeSingleton.h +0 -68
- data/ext/iCuke/sdk4.0/ViewResponse.h +0 -5
- data/ext/iCuke/sdk4.0/ViewResponse.m +0 -84
- data/ext/iCuke/sdk4.0/Viewer.h +0 -8
- data/ext/iCuke/sdk4.0/iCukeHTTPResponseHandler.h +0 -50
- data/ext/iCuke/sdk4.0/iCukeHTTPResponseHandler.m +0 -381
- data/ext/iCuke/sdk4.0/iCukeHTTPServer.h +0 -53
- data/ext/iCuke/sdk4.0/iCukeServer.h +0 -14
- data/ext/iCuke/sdk4.0/iCukeServer.m +0 -65
- data/ext/iCuke/sdk4.0/json/JSON.h +0 -50
- data/ext/iCuke/sdk4.0/json/NSObject+SBJSON.h +0 -68
- data/ext/iCuke/sdk4.0/json/NSObject+SBJSON.m +0 -53
- data/ext/iCuke/sdk4.0/json/NSString+SBJSON.h +0 -58
- data/ext/iCuke/sdk4.0/json/NSString+SBJSON.m +0 -55
- data/ext/iCuke/sdk4.0/json/SBJSON.h +0 -75
- data/ext/iCuke/sdk4.0/json/SBJSON.m +0 -212
- data/ext/iCuke/sdk4.0/json/SBJsonBase.h +0 -86
- data/ext/iCuke/sdk4.0/json/SBJsonBase.m +0 -78
- data/ext/iCuke/sdk4.0/json/SBJsonParser.h +0 -87
- data/ext/iCuke/sdk4.0/json/SBJsonParser.m +0 -475
- data/ext/iCuke/sdk4.0/json/SBJsonWriter.h +0 -129
- data/ext/iCuke/sdk4.0/json/SBJsonWriter.m +0 -228
@@ -1,68 +0,0 @@
|
|
1
|
-
#import "RecorderResponse.h"
|
2
|
-
#import "iCukeHTTPServer.h"
|
3
|
-
#import "Recorder.h"
|
4
|
-
|
5
|
-
@implementation RecorderResponse
|
6
|
-
+ (void)load
|
7
|
-
{
|
8
|
-
[iCukeHTTPResponseHandler registerHandler:self];
|
9
|
-
}
|
10
|
-
|
11
|
-
+ (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest
|
12
|
-
method:(NSString *)requestMethod
|
13
|
-
url:(NSURL *)requestURL
|
14
|
-
headerFields:(NSDictionary *)requestHeaderFields
|
15
|
-
{
|
16
|
-
if ([requestURL.path isEqualToString:@"/record"] ||
|
17
|
-
[requestURL.path isEqualToString:@"/play"] ||
|
18
|
-
[requestURL.path isEqualToString:@"/load"] ||
|
19
|
-
[requestURL.path isEqualToString:@"/save"] ||
|
20
|
-
[requestURL.path isEqualToString:@"/stop"])
|
21
|
-
return YES;
|
22
|
-
|
23
|
-
return NO;
|
24
|
-
}
|
25
|
-
|
26
|
-
- (void)startResponse
|
27
|
-
{
|
28
|
-
if ([url.path isEqualToString:@"/record"]) {
|
29
|
-
[[Recorder sharedRecorder] record];
|
30
|
-
[self finishResponse];
|
31
|
-
} else if ([url.path isEqualToString:@"/play"]) {
|
32
|
-
[[Recorder sharedRecorder] playbackWithDelegate: self doneSelector: @selector(finishResponse)];
|
33
|
-
} else if ([url.path isEqualToString:@"/load"]) {
|
34
|
-
[[Recorder sharedRecorder] loadFromFile: [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
35
|
-
[self finishResponse];
|
36
|
-
} else if ([url.path isEqualToString:@"/save"]) {
|
37
|
-
[[Recorder sharedRecorder] saveToFile: [[url query] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
|
38
|
-
[self finishResponse];
|
39
|
-
} else if ([url.path isEqualToString:@"/stop"]) {
|
40
|
-
[[Recorder sharedRecorder] stop];
|
41
|
-
[self finishResponse];
|
42
|
-
}
|
43
|
-
|
44
|
-
}
|
45
|
-
|
46
|
-
- (void)finishResponse
|
47
|
-
{
|
48
|
-
CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
|
49
|
-
CFHTTPMessageSetHeaderFieldValue(response, (CFStringRef)@"Connection", (CFStringRef)@"close");
|
50
|
-
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
|
51
|
-
|
52
|
-
@try
|
53
|
-
{
|
54
|
-
[fileHandle writeData:(NSData *)headerData];
|
55
|
-
}
|
56
|
-
@catch (NSException *exception)
|
57
|
-
{
|
58
|
-
// Ignore the exception, it normally just means the client
|
59
|
-
// closed the connection from the other end.
|
60
|
-
}
|
61
|
-
@finally
|
62
|
-
{
|
63
|
-
CFRelease(headerData);
|
64
|
-
[server closeHandler:self];
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
@end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
//
|
2
|
-
// SynthesizeSingleton.h
|
3
|
-
// iTrackSportsBets
|
4
|
-
//
|
5
|
-
// Created by Matt Gallagher on 20/10/08.
|
6
|
-
// Copyright 2008 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
|
-
#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \
|
16
|
-
\
|
17
|
-
static classname *shared##classname = nil; \
|
18
|
-
\
|
19
|
-
+ (classname *)shared##classname \
|
20
|
-
{ \
|
21
|
-
@synchronized(self) \
|
22
|
-
{ \
|
23
|
-
if (shared##classname == nil) \
|
24
|
-
{ \
|
25
|
-
shared##classname = [[self alloc] init]; \
|
26
|
-
} \
|
27
|
-
} \
|
28
|
-
\
|
29
|
-
return shared##classname; \
|
30
|
-
} \
|
31
|
-
\
|
32
|
-
+ (id)allocWithZone:(NSZone *)zone \
|
33
|
-
{ \
|
34
|
-
@synchronized(self) \
|
35
|
-
{ \
|
36
|
-
if (shared##classname == nil) \
|
37
|
-
{ \
|
38
|
-
shared##classname = [super allocWithZone:zone]; \
|
39
|
-
return shared##classname; \
|
40
|
-
} \
|
41
|
-
} \
|
42
|
-
\
|
43
|
-
return nil; \
|
44
|
-
} \
|
45
|
-
\
|
46
|
-
- (id)copyWithZone:(NSZone *)zone \
|
47
|
-
{ \
|
48
|
-
return self; \
|
49
|
-
} \
|
50
|
-
\
|
51
|
-
- (id)retain \
|
52
|
-
{ \
|
53
|
-
return self; \
|
54
|
-
} \
|
55
|
-
\
|
56
|
-
- (NSUInteger)retainCount \
|
57
|
-
{ \
|
58
|
-
return NSUIntegerMax; \
|
59
|
-
} \
|
60
|
-
\
|
61
|
-
- (void)release \
|
62
|
-
{ \
|
63
|
-
} \
|
64
|
-
\
|
65
|
-
- (id)autorelease \
|
66
|
-
{ \
|
67
|
-
return self; \
|
68
|
-
}
|
@@ -1,84 +0,0 @@
|
|
1
|
-
#import "ViewResponse.h"
|
2
|
-
#import "iCukeHTTPServer.h"
|
3
|
-
#import "Viewer.h"
|
4
|
-
|
5
|
-
// AX API
|
6
|
-
extern Boolean AXAPIEnabled(void);
|
7
|
-
|
8
|
-
@implementation ViewResponse
|
9
|
-
+ (void)load
|
10
|
-
{
|
11
|
-
[iCukeHTTPResponseHandler registerHandler:self];
|
12
|
-
}
|
13
|
-
|
14
|
-
+ (BOOL)canHandleRequest:(CFHTTPMessageRef)aRequest
|
15
|
-
method:(NSString *)requestMethod
|
16
|
-
url:(NSURL *)requestURL
|
17
|
-
headerFields:(NSDictionary *)requestHeaderFields
|
18
|
-
{
|
19
|
-
return [requestURL.path isEqualToString:@"/view"];
|
20
|
-
}
|
21
|
-
|
22
|
-
- (void)startResponse
|
23
|
-
{
|
24
|
-
if (!AXAPIEnabled()) {
|
25
|
-
CFHTTPMessageRef response =
|
26
|
-
CFHTTPMessageCreateResponse(
|
27
|
-
kCFAllocatorDefault, 500, NULL, kCFHTTPVersion1_1);
|
28
|
-
CFHTTPMessageSetHeaderFieldValue(
|
29
|
-
response, (CFStringRef)@"Content-Type", (CFStringRef)@"text/plain");
|
30
|
-
CFHTTPMessageSetHeaderFieldValue(
|
31
|
-
response, (CFStringRef)@"Connection", (CFStringRef)@"close");
|
32
|
-
CFHTTPMessageSetBody(
|
33
|
-
response,
|
34
|
-
(CFDataRef)[[NSString stringWithFormat:
|
35
|
-
@"Accessiblity Inspector Disabled: "
|
36
|
-
@"Please enable the accessibilty inspector in the simulator and retry"]
|
37
|
-
dataUsingEncoding:NSUTF8StringEncoding]);
|
38
|
-
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
|
39
|
-
@try
|
40
|
-
{
|
41
|
-
[fileHandle writeData:(NSData *)headerData];
|
42
|
-
}
|
43
|
-
@catch (NSException *exception)
|
44
|
-
{
|
45
|
-
// Ignore the exception, it normally just means the client
|
46
|
-
// closed the connection from the other end.
|
47
|
-
}
|
48
|
-
@finally
|
49
|
-
{
|
50
|
-
CFRelease(headerData);
|
51
|
-
CFRelease(response);
|
52
|
-
[server closeHandler:self];
|
53
|
-
}
|
54
|
-
|
55
|
-
return;
|
56
|
-
}
|
57
|
-
|
58
|
-
CFHTTPMessageRef response = CFHTTPMessageCreateResponse(kCFAllocatorDefault, 200, NULL, kCFHTTPVersion1_1);
|
59
|
-
CFHTTPMessageSetHeaderFieldValue(response, (CFStringRef)@"Content-Type", (CFStringRef)@"text/xml");
|
60
|
-
CFHTTPMessageSetHeaderFieldValue(response, (CFStringRef)@"Connection", (CFStringRef)@"close");
|
61
|
-
|
62
|
-
NSData *viewData = [[[Viewer sharedViewer] screen] dataUsingEncoding:NSUTF8StringEncoding];
|
63
|
-
|
64
|
-
CFHTTPMessageSetHeaderFieldValue(response, (CFStringRef)@"Content-Length",
|
65
|
-
(CFStringRef)[NSString stringWithFormat:@"%ld", [viewData length]]);
|
66
|
-
CFDataRef headerData = CFHTTPMessageCopySerializedMessage(response);
|
67
|
-
|
68
|
-
@try
|
69
|
-
{
|
70
|
-
[fileHandle writeData:(NSData *)headerData];
|
71
|
-
[fileHandle writeData:viewData];
|
72
|
-
}
|
73
|
-
@catch (NSException *exception)
|
74
|
-
{
|
75
|
-
// Ignore the exception, it normally just means the client
|
76
|
-
// closed the connection from the other end.
|
77
|
-
}
|
78
|
-
@finally
|
79
|
-
{
|
80
|
-
CFRelease(headerData);
|
81
|
-
[server closeHandler:self];
|
82
|
-
}
|
83
|
-
}
|
84
|
-
@end
|
data/ext/iCuke/sdk4.0/Viewer.h
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
//
|
2
|
-
// HTTPResponseHandler.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
|
-
#import <CFNetwork/CFNetwork.h>
|
18
|
-
#else
|
19
|
-
#import <Cocoa/Cocoa.h>
|
20
|
-
#endif
|
21
|
-
|
22
|
-
@class iCukeHTTPServer;
|
23
|
-
|
24
|
-
@interface iCukeHTTPResponseHandler : NSObject
|
25
|
-
{
|
26
|
-
CFHTTPMessageRef request;
|
27
|
-
NSString *requestMethod;
|
28
|
-
NSDictionary *headerFields;
|
29
|
-
NSFileHandle *fileHandle;
|
30
|
-
iCukeHTTPServer *server;
|
31
|
-
NSURL *url;
|
32
|
-
}
|
33
|
-
|
34
|
-
+ (NSUInteger)priority;
|
35
|
-
+ (void)registerHandler:(Class)handlerClass;
|
36
|
-
|
37
|
-
+ (iCukeHTTPResponseHandler *)handlerForRequest:(CFHTTPMessageRef)aRequest
|
38
|
-
fileHandle:(NSFileHandle *)requestFileHandle
|
39
|
-
server:(iCukeHTTPServer *)aServer;
|
40
|
-
|
41
|
-
- (id)initWithRequest:(CFHTTPMessageRef)aRequest
|
42
|
-
method:(NSString *)method
|
43
|
-
url:(NSURL *)requestURL
|
44
|
-
headerFields:(NSDictionary *)requestHeaderFields
|
45
|
-
fileHandle:(NSFileHandle *)requestFileHandle
|
46
|
-
server:(iCukeHTTPServer *)aServer;
|
47
|
-
- (void)startResponse;
|
48
|
-
- (void)endResponse;
|
49
|
-
|
50
|
-
@end
|
@@ -1,381 +0,0 @@
|
|
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
|