appium-webdriveragent 16.6.0 → 16.7.0
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.
- package/CHANGELOG.md +6 -0
- package/WebDriverAgent.xcodeproj/project.pbxproj +45 -303
- package/WebDriverAgentLib/Info.plist +2 -2
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.h → FBHTTPServer.h} +11 -7
- package/WebDriverAgentLib/Routing/{WatchOS/FBWatchHTTPServer.m → FBHTTPServer.m} +26 -13
- package/WebDriverAgentLib/Routing/FBTCPSocket.h +10 -45
- package/WebDriverAgentLib/Routing/FBTCPSocket.m +12 -94
- package/WebDriverAgentLib/Routing/FBWebServer.h +1 -1
- package/WebDriverAgentLib/Routing/FBWebServer.m +4 -49
- package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.h → RouteRequest.h} +2 -4
- package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.h → RouteResponse.h} +2 -2
- package/WebDriverAgentLib/Utilities/FBMjpegServer.h +3 -5
- package/WebDriverAgentLib/Utilities/FBMjpegServer.m +1 -66
- package/package.json +1 -1
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.h +0 -1220
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncSocket.m +0 -8786
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.h +0 -1036
- package/WebDriverAgentLib/Vendor/CocoaAsyncSocket/GCDAsyncUdpSocket.m +0 -5868
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.h +0 -12
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDNumber.m +0 -88
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.h +0 -56
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Categories/DDRange.m +0 -100
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.h +0 -109
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPConnection.m +0 -2281
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPLogging.h +0 -122
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.h +0 -53
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPMessage.m +0 -357
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPResponse.h +0 -149
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.h +0 -126
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/HTTPServer.m +0 -372
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/LICENSE +0 -18
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.h +0 -13
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPDataResponse.m +0 -83
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.h +0 -9
- package/WebDriverAgentLib/Vendor/CocoaHTTPServer/Responses/HTTPErrorResponse.m +0 -38
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.h +0 -13
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/HTTPResponseProxy.m +0 -84
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/LICENSE +0 -19
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.h +0 -18
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/Route.m +0 -11
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.h +0 -16
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteRequest.m +0 -50
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.h +0 -20
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RouteResponse.m +0 -66
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.h +0 -5
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingConnection.m +0 -142
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.h +0 -55
- package/WebDriverAgentLib/Vendor/RoutingHTTPServer/RoutingHTTPServer.m +0 -303
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteRequest.m → RouteRequest.m} +0 -0
- /package/WebDriverAgentLib/Routing/{WatchOS/RouteResponse.m → RouteResponse.m} +0 -0
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* In order to provide fast and flexible logging, this project uses Cocoa Lumberjack.
|
|
3
|
-
*
|
|
4
|
-
* The Google Code page has a wealth of documentation if you have any questions.
|
|
5
|
-
* https://github.com/robbiehanson/CocoaLumberjack
|
|
6
|
-
*
|
|
7
|
-
* Here's what you need to know concerning how logging is setup for CocoaHTTPServer:
|
|
8
|
-
*
|
|
9
|
-
* There are 4 log levels:
|
|
10
|
-
* - Error
|
|
11
|
-
* - Warning
|
|
12
|
-
* - Info
|
|
13
|
-
* - Verbose
|
|
14
|
-
*
|
|
15
|
-
* In addition to this, there is a Trace flag that can be enabled.
|
|
16
|
-
* When tracing is enabled, it spits out the methods that are being called.
|
|
17
|
-
*
|
|
18
|
-
* Please note that tracing is separate from the log levels.
|
|
19
|
-
* For example, one could set the log level to warning, and enable tracing.
|
|
20
|
-
*
|
|
21
|
-
* All logging is asynchronous, except errors.
|
|
22
|
-
* To use logging within your own custom files, follow the steps below.
|
|
23
|
-
*
|
|
24
|
-
* Step 1:
|
|
25
|
-
* Import this header in your implementation file:
|
|
26
|
-
*
|
|
27
|
-
* #import "HTTPLogging.h"
|
|
28
|
-
*
|
|
29
|
-
* Step 2:
|
|
30
|
-
* Define your logging level in your implementation file:
|
|
31
|
-
*
|
|
32
|
-
* // Log levels: off, error, warn, info, verbose
|
|
33
|
-
* static const int httpLogLevel = HTTP_LOG_LEVEL_VERBOSE;
|
|
34
|
-
*
|
|
35
|
-
* If you wish to enable tracing, you could do something like this:
|
|
36
|
-
*
|
|
37
|
-
* // Debug levels: off, error, warn, info, verbose
|
|
38
|
-
* static const int httpLogLevel = HTTP_LOG_LEVEL_INFO | HTTP_LOG_FLAG_TRACE;
|
|
39
|
-
*
|
|
40
|
-
* Step 3:
|
|
41
|
-
* Replace your NSLog statements with HTTPLog statements according to the severity of the message.
|
|
42
|
-
*
|
|
43
|
-
* NSLog(@"Fatal error, no dohickey found!"); -> HTTPLogError(@"Fatal error, no dohickey found!");
|
|
44
|
-
*
|
|
45
|
-
* HTTPLog works exactly the same as NSLog.
|
|
46
|
-
* This means you can pass it multiple variables just like NSLog.
|
|
47
|
-
**/
|
|
48
|
-
|
|
49
|
-
// Define logging context for every log message coming from the HTTP server.
|
|
50
|
-
// The logging context can be extracted from the DDLogMessage from within the logging framework,
|
|
51
|
-
// which gives loggers, formatters, and filters the ability to optionally process them differently.
|
|
52
|
-
|
|
53
|
-
#define HTTP_LOG_CONTEXT 80
|
|
54
|
-
|
|
55
|
-
// Configure log levels.
|
|
56
|
-
|
|
57
|
-
#define HTTP_LOG_FLAG_ERROR (1 << 0) // 0...00001
|
|
58
|
-
#define HTTP_LOG_FLAG_WARN (1 << 1) // 0...00010
|
|
59
|
-
#define HTTP_LOG_FLAG_INFO (1 << 2) // 0...00100
|
|
60
|
-
#define HTTP_LOG_FLAG_VERBOSE (1 << 3) // 0...01000
|
|
61
|
-
|
|
62
|
-
#define HTTP_LOG_LEVEL_OFF 0 // 0...00000
|
|
63
|
-
#define HTTP_LOG_LEVEL_ERROR (HTTP_LOG_LEVEL_OFF | HTTP_LOG_FLAG_ERROR) // 0...00001
|
|
64
|
-
#define HTTP_LOG_LEVEL_WARN (HTTP_LOG_LEVEL_ERROR | HTTP_LOG_FLAG_WARN) // 0...00011
|
|
65
|
-
#define HTTP_LOG_LEVEL_INFO (HTTP_LOG_LEVEL_WARN | HTTP_LOG_FLAG_INFO) // 0...00111
|
|
66
|
-
#define HTTP_LOG_LEVEL_VERBOSE (HTTP_LOG_LEVEL_INFO | HTTP_LOG_FLAG_VERBOSE) // 0...01111
|
|
67
|
-
|
|
68
|
-
// Setup fine grained logging.
|
|
69
|
-
// The first 4 bits are being used by the standard log levels (0 - 3)
|
|
70
|
-
//
|
|
71
|
-
// We're going to add tracing, but NOT as a log level.
|
|
72
|
-
// Tracing can be turned on and off independently of log level.
|
|
73
|
-
|
|
74
|
-
#define HTTP_LOG_FLAG_TRACE (1 << 4) // 0...10000
|
|
75
|
-
|
|
76
|
-
// Setup the usual boolean macros.
|
|
77
|
-
|
|
78
|
-
#define HTTP_LOG_ERROR (httpLogLevel & HTTP_LOG_FLAG_ERROR)
|
|
79
|
-
#define HTTP_LOG_WARN (httpLogLevel & HTTP_LOG_FLAG_WARN)
|
|
80
|
-
#define HTTP_LOG_INFO (httpLogLevel & HTTP_LOG_FLAG_INFO)
|
|
81
|
-
#define HTTP_LOG_VERBOSE (httpLogLevel & HTTP_LOG_FLAG_VERBOSE)
|
|
82
|
-
#define HTTP_LOG_TRACE (httpLogLevel & HTTP_LOG_FLAG_TRACE)
|
|
83
|
-
|
|
84
|
-
// Configure asynchronous logging.
|
|
85
|
-
// We follow the default configuration,
|
|
86
|
-
// but we reserve a special macro to easily disable asynchronous logging for debugging purposes.
|
|
87
|
-
|
|
88
|
-
#define HTTP_LOG_ASYNC_ENABLED YES
|
|
89
|
-
|
|
90
|
-
#define HTTP_LOG_ASYNC_ERROR ( NO && HTTP_LOG_ASYNC_ENABLED)
|
|
91
|
-
#define HTTP_LOG_ASYNC_WARN (YES && HTTP_LOG_ASYNC_ENABLED)
|
|
92
|
-
#define HTTP_LOG_ASYNC_INFO (YES && HTTP_LOG_ASYNC_ENABLED)
|
|
93
|
-
#define HTTP_LOG_ASYNC_VERBOSE (YES && HTTP_LOG_ASYNC_ENABLED)
|
|
94
|
-
#define HTTP_LOG_ASYNC_TRACE (YES && HTTP_LOG_ASYNC_ENABLED)
|
|
95
|
-
|
|
96
|
-
// Define logging primitives.
|
|
97
|
-
|
|
98
|
-
#define HTTPLogError(...) do {} while (0)
|
|
99
|
-
|
|
100
|
-
#define HTTPLogWarn(...) do {} while (0)
|
|
101
|
-
|
|
102
|
-
#define HTTPLogInfo(...) do {} while (0)
|
|
103
|
-
|
|
104
|
-
#define HTTPLogVerbose(...) do {} while (0)
|
|
105
|
-
|
|
106
|
-
#define HTTPLogTrace() do {} while (0)
|
|
107
|
-
|
|
108
|
-
#define HTTPLogTrace2(...) do {} while (0)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
#define HTTPLogCError(...) do {} while (0)
|
|
112
|
-
|
|
113
|
-
#define HTTPLogCWarn(...) do {} while (0)
|
|
114
|
-
|
|
115
|
-
#define HTTPLogCInfo(...) do {} while (0)
|
|
116
|
-
|
|
117
|
-
#define HTTPLogCVerbose(...) do {} while (0)
|
|
118
|
-
|
|
119
|
-
#define HTTPLogCTrace() do {} while (0)
|
|
120
|
-
|
|
121
|
-
#define HTTPLogCTrace2(...) do {} while (0)
|
|
122
|
-
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The HTTPMessage class is a simple Objective-C wrapper for HTTP message parsing.
|
|
3
|
-
* Migrated from CFHTTPMessage to use Foundation and Network framework.
|
|
4
|
-
**/
|
|
5
|
-
|
|
6
|
-
#import <Foundation/Foundation.h>
|
|
7
|
-
|
|
8
|
-
#define HTTPVersion1_0 @"HTTP/1.0"
|
|
9
|
-
#define HTTPVersion1_1 @"HTTP/1.1"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
@interface HTTPMessage : NSObject
|
|
13
|
-
{
|
|
14
|
-
NSMutableDictionary *_headers;
|
|
15
|
-
NSMutableData *_body;
|
|
16
|
-
NSString *_version;
|
|
17
|
-
NSString *_method;
|
|
18
|
-
NSURL *_url;
|
|
19
|
-
NSInteger _statusCode;
|
|
20
|
-
NSString *_statusDescription;
|
|
21
|
-
BOOL _isRequest;
|
|
22
|
-
BOOL _headerComplete;
|
|
23
|
-
NSMutableData *_rawData;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
- (id)initEmptyRequest;
|
|
27
|
-
|
|
28
|
-
- (id)initRequestWithMethod:(NSString *)method URL:(NSURL *)url version:(NSString *)version;
|
|
29
|
-
|
|
30
|
-
- (id)initResponseWithStatusCode:(NSInteger)code description:(NSString *)description version:(NSString *)version;
|
|
31
|
-
|
|
32
|
-
- (BOOL)appendData:(NSData *)data;
|
|
33
|
-
|
|
34
|
-
- (BOOL)isHeaderComplete;
|
|
35
|
-
|
|
36
|
-
- (NSString *)version;
|
|
37
|
-
|
|
38
|
-
- (NSString *)method;
|
|
39
|
-
- (NSURL *)url;
|
|
40
|
-
|
|
41
|
-
- (NSInteger)statusCode;
|
|
42
|
-
|
|
43
|
-
- (NSDictionary *)allHeaderFields;
|
|
44
|
-
- (NSString *)headerField:(NSString *)headerField;
|
|
45
|
-
|
|
46
|
-
- (void)setHeaderField:(NSString *)headerField value:(NSString *)headerFieldValue;
|
|
47
|
-
|
|
48
|
-
- (NSData *)messageData;
|
|
49
|
-
|
|
50
|
-
- (NSData *)body;
|
|
51
|
-
- (void)setBody:(NSData *)body;
|
|
52
|
-
|
|
53
|
-
@end
|
|
@@ -1,357 +0,0 @@
|
|
|
1
|
-
#import "HTTPMessage.h"
|
|
2
|
-
|
|
3
|
-
#if ! __has_feature(objc_arc)
|
|
4
|
-
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
|
5
|
-
#endif
|
|
6
|
-
|
|
7
|
-
#pragma clang diagnostic ignored "-Wdirect-ivar-access"
|
|
8
|
-
|
|
9
|
-
@implementation HTTPMessage
|
|
10
|
-
|
|
11
|
-
- (id)init
|
|
12
|
-
{
|
|
13
|
-
if ((self = [super init]))
|
|
14
|
-
{
|
|
15
|
-
_headers = [[NSMutableDictionary alloc] init];
|
|
16
|
-
_body = [[NSMutableData alloc] init];
|
|
17
|
-
_rawData = [[NSMutableData alloc] init];
|
|
18
|
-
_version = HTTPVersion1_1;
|
|
19
|
-
_headerComplete = NO;
|
|
20
|
-
_isRequest = YES;
|
|
21
|
-
}
|
|
22
|
-
return self;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
- (id)initEmptyRequest
|
|
26
|
-
{
|
|
27
|
-
if ((self = [self init]))
|
|
28
|
-
{
|
|
29
|
-
_isRequest = YES;
|
|
30
|
-
}
|
|
31
|
-
return self;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
- (id)initRequestWithMethod:(NSString *)method URL:(NSURL *)url version:(NSString *)version
|
|
35
|
-
{
|
|
36
|
-
if ((self = [self init]))
|
|
37
|
-
{
|
|
38
|
-
_isRequest = YES;
|
|
39
|
-
_method = [method copy];
|
|
40
|
-
_url = [url copy];
|
|
41
|
-
_version = version ? [version copy] : HTTPVersion1_1;
|
|
42
|
-
}
|
|
43
|
-
return self;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
- (id)initResponseWithStatusCode:(NSInteger)code description:(NSString *)description version:(NSString *)version
|
|
47
|
-
{
|
|
48
|
-
if ((self = [self init]))
|
|
49
|
-
{
|
|
50
|
-
_isRequest = NO;
|
|
51
|
-
_statusCode = code;
|
|
52
|
-
_statusDescription = [description copy];
|
|
53
|
-
_version = version ? [version copy] : HTTPVersion1_1;
|
|
54
|
-
}
|
|
55
|
-
return self;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
- (BOOL)appendData:(NSData *)data
|
|
59
|
-
{
|
|
60
|
-
if (!data || [data length] == 0)
|
|
61
|
-
{
|
|
62
|
-
return NO;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
[_rawData appendData:data];
|
|
66
|
-
|
|
67
|
-
if (!_headerComplete)
|
|
68
|
-
{
|
|
69
|
-
// Look for the end of headers (CRLF CRLF or LF LF)
|
|
70
|
-
NSData *headerEndMarker = [@"\r\n\r\n" dataUsingEncoding:NSASCIIStringEncoding];
|
|
71
|
-
NSRange headerEndRange = [_rawData rangeOfData:headerEndMarker options:(NSDataSearchOptions)0 range:NSMakeRange(0, [_rawData length])];
|
|
72
|
-
|
|
73
|
-
if (headerEndRange.location == NSNotFound)
|
|
74
|
-
{
|
|
75
|
-
// Also check for LF LF (some clients use this)
|
|
76
|
-
NSData *lfMarker = [@"\n\n" dataUsingEncoding:NSASCIIStringEncoding];
|
|
77
|
-
headerEndRange = [_rawData rangeOfData:lfMarker options:(NSDataSearchOptions)0 range:NSMakeRange(0, [_rawData length])];
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if (headerEndRange.location != NSNotFound)
|
|
81
|
-
{
|
|
82
|
-
_headerComplete = YES;
|
|
83
|
-
|
|
84
|
-
// Parse the header data
|
|
85
|
-
NSData *headerData = [_rawData subdataWithRange:NSMakeRange(0, headerEndRange.location + headerEndRange.length)];
|
|
86
|
-
NSString *headerString = [[NSString alloc] initWithData:headerData encoding:NSASCIIStringEncoding];
|
|
87
|
-
|
|
88
|
-
if (headerString)
|
|
89
|
-
{
|
|
90
|
-
[self parseHeaders:headerString];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Extract body data if any
|
|
94
|
-
NSUInteger bodyStart = headerEndRange.location + headerEndRange.length;
|
|
95
|
-
if ([_rawData length] > bodyStart)
|
|
96
|
-
{
|
|
97
|
-
NSData *bodyData = [_rawData subdataWithRange:NSMakeRange(bodyStart, [_rawData length] - bodyStart)];
|
|
98
|
-
[_body appendData:bodyData];
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
[_rawData setLength:0];
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
else
|
|
105
|
-
{
|
|
106
|
-
// Headers are complete, append to body
|
|
107
|
-
[_body appendData:data];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return YES;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
- (void)parseHeaders:(NSString *)headerString
|
|
114
|
-
{
|
|
115
|
-
NSArray *lines;
|
|
116
|
-
|
|
117
|
-
// Try splitting by "\r\n" first (standard HTTP line ending)
|
|
118
|
-
// Check if the string actually contains "\r\n" delimiter
|
|
119
|
-
if ([headerString rangeOfString:@"\r\n"].location != NSNotFound)
|
|
120
|
-
{
|
|
121
|
-
// Found "\r\n" delimiter, use this split
|
|
122
|
-
lines = [headerString componentsSeparatedByString:@"\r\n"];
|
|
123
|
-
}
|
|
124
|
-
else
|
|
125
|
-
{
|
|
126
|
-
// No "\r\n" found, try "\n" (some clients use just LF)
|
|
127
|
-
lines = [headerString componentsSeparatedByString:@"\n"];
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// componentsSeparatedByString: always returns at least one element,
|
|
131
|
-
// so check if we have meaningful content (non-empty first line)
|
|
132
|
-
if ([lines count] == 0 || [[lines objectAtIndex:0] length] == 0)
|
|
133
|
-
{
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// Parse first line (request line or status line)
|
|
138
|
-
NSString *firstLine = [lines objectAtIndex:0];
|
|
139
|
-
NSArray *firstLineParts = [firstLine componentsSeparatedByString:@" "];
|
|
140
|
-
|
|
141
|
-
if (_isRequest && [firstLineParts count] >= 3)
|
|
142
|
-
{
|
|
143
|
-
// Request line: METHOD URL VERSION
|
|
144
|
-
_method = [[firstLineParts objectAtIndex:0] copy];
|
|
145
|
-
NSString *urlString = [firstLineParts objectAtIndex:1];
|
|
146
|
-
|
|
147
|
-
// Handle both absolute URLs and relative paths
|
|
148
|
-
// Try absolute URL first
|
|
149
|
-
NSURL *parsedURL = [NSURL URLWithString:urlString];
|
|
150
|
-
|
|
151
|
-
// If that fails (nil), it's likely a relative path like "/endpoint"
|
|
152
|
-
// Create a URL with a base URL to handle relative paths
|
|
153
|
-
if (!parsedURL)
|
|
154
|
-
{
|
|
155
|
-
// Use a dummy base URL to allow relative path parsing
|
|
156
|
-
NSURL *baseURL = [NSURL URLWithString:@"http://localhost"];
|
|
157
|
-
parsedURL = [NSURL URLWithString:urlString relativeToURL:baseURL];
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
_url = [parsedURL copy];
|
|
161
|
-
if ([firstLineParts count] >= 3)
|
|
162
|
-
{
|
|
163
|
-
_version = [[firstLineParts objectAtIndex:2] copy];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
else if (!_isRequest && [firstLineParts count] >= 3)
|
|
167
|
-
{
|
|
168
|
-
// Status line: VERSION CODE DESCRIPTION
|
|
169
|
-
_version = [[firstLineParts objectAtIndex:0] copy];
|
|
170
|
-
_statusCode = [[firstLineParts objectAtIndex:1] integerValue];
|
|
171
|
-
NSMutableArray *descParts = [NSMutableArray arrayWithArray:firstLineParts];
|
|
172
|
-
[descParts removeObjectAtIndex:0];
|
|
173
|
-
[descParts removeObjectAtIndex:0];
|
|
174
|
-
_statusDescription = [[descParts componentsJoinedByString:@" "] copy];
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Parse header fields
|
|
178
|
-
for (NSUInteger i = 1; i < [lines count]; i++)
|
|
179
|
-
{
|
|
180
|
-
NSString *line = [lines objectAtIndex:i];
|
|
181
|
-
if ([line length] == 0)
|
|
182
|
-
{
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
NSRange colonRange = [line rangeOfString:@":"];
|
|
187
|
-
if (colonRange.location != NSNotFound)
|
|
188
|
-
{
|
|
189
|
-
NSString *headerName = [[line substringToIndex:colonRange.location] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
190
|
-
NSString *headerValue = [[line substringFromIndex:colonRange.location + 1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
|
|
191
|
-
|
|
192
|
-
if ([headerName length] > 0)
|
|
193
|
-
{
|
|
194
|
-
// HTTP headers are case-insensitive, but we'll store them with their original case
|
|
195
|
-
// For lookup, we'll use case-insensitive comparison
|
|
196
|
-
[_headers setObject:headerValue forKey:headerName];
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
- (BOOL)isHeaderComplete
|
|
203
|
-
{
|
|
204
|
-
return _headerComplete;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
- (NSString *)version
|
|
208
|
-
{
|
|
209
|
-
return _version;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
- (NSString *)method
|
|
213
|
-
{
|
|
214
|
-
return _method;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
- (NSURL *)url
|
|
218
|
-
{
|
|
219
|
-
return _url;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
- (NSInteger)statusCode
|
|
223
|
-
{
|
|
224
|
-
return _statusCode;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
- (NSDictionary *)allHeaderFields
|
|
228
|
-
{
|
|
229
|
-
return [_headers copy];
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
- (NSString *)headerField:(NSString *)headerField
|
|
233
|
-
{
|
|
234
|
-
// Case-insensitive lookup
|
|
235
|
-
for (NSString *key in [_headers allKeys])
|
|
236
|
-
{
|
|
237
|
-
if ([key caseInsensitiveCompare:headerField] == NSOrderedSame)
|
|
238
|
-
{
|
|
239
|
-
return [_headers objectForKey:key];
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return nil;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
- (void)setHeaderField:(NSString *)headerField value:(NSString *)headerFieldValue
|
|
246
|
-
{
|
|
247
|
-
if (headerField && headerFieldValue)
|
|
248
|
-
{
|
|
249
|
-
// Remove existing header with same name (case-insensitive)
|
|
250
|
-
NSMutableArray *keysToRemove = [NSMutableArray array];
|
|
251
|
-
for (NSString *key in [_headers allKeys])
|
|
252
|
-
{
|
|
253
|
-
if ([key caseInsensitiveCompare:headerField] == NSOrderedSame)
|
|
254
|
-
{
|
|
255
|
-
[keysToRemove addObject:key];
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
[_headers removeObjectsForKeys:keysToRemove];
|
|
259
|
-
|
|
260
|
-
// Add new header
|
|
261
|
-
[_headers setObject:headerFieldValue forKey:headerField];
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
- (NSData *)messageData
|
|
266
|
-
{
|
|
267
|
-
NSMutableString *messageString = [NSMutableString string];
|
|
268
|
-
|
|
269
|
-
if (_isRequest)
|
|
270
|
-
{
|
|
271
|
-
// Request line
|
|
272
|
-
// For relative URLs, use the path component; for absolute URLs, use absoluteString
|
|
273
|
-
NSString *urlString = nil;
|
|
274
|
-
if (_url)
|
|
275
|
-
{
|
|
276
|
-
// If it's a relative URL (has a base), use the relative path
|
|
277
|
-
// Otherwise use absoluteString or path
|
|
278
|
-
if ([_url baseURL])
|
|
279
|
-
{
|
|
280
|
-
// Relative URL - use the relative portion
|
|
281
|
-
urlString = [_url relativeString];
|
|
282
|
-
}
|
|
283
|
-
else
|
|
284
|
-
{
|
|
285
|
-
// Absolute URL
|
|
286
|
-
urlString = [_url absoluteString];
|
|
287
|
-
if (!urlString)
|
|
288
|
-
{
|
|
289
|
-
urlString = [_url path];
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
[messageString appendFormat:@"%@ %@ %@\r\n", _method ?: @"GET", urlString ?: @"/", _version ?: HTTPVersion1_1];
|
|
294
|
-
}
|
|
295
|
-
else
|
|
296
|
-
{
|
|
297
|
-
// Status line
|
|
298
|
-
[messageString appendFormat:@"%@ %ld %@\r\n", _version ?: HTTPVersion1_1, (long)_statusCode, _statusDescription ?: @""];
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
// Headers
|
|
302
|
-
for (NSString *key in [_headers allKeys])
|
|
303
|
-
{
|
|
304
|
-
NSString *value = [_headers objectForKey:key];
|
|
305
|
-
[messageString appendFormat:@"%@: %@\r\n", key, value];
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Empty line to separate headers from body
|
|
309
|
-
[messageString appendString:@"\r\n"];
|
|
310
|
-
|
|
311
|
-
NSMutableData *data = [NSMutableData dataWithData:(id)[messageString dataUsingEncoding:NSASCIIStringEncoding]];
|
|
312
|
-
|
|
313
|
-
// Append body if present
|
|
314
|
-
if ([_body length] > 0)
|
|
315
|
-
{
|
|
316
|
-
[data appendData:_body];
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
return data;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
- (NSData *)body
|
|
323
|
-
{
|
|
324
|
-
return [_body copy];
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
- (void)setBody:(NSData *)body
|
|
328
|
-
{
|
|
329
|
-
if (body)
|
|
330
|
-
{
|
|
331
|
-
_body = [body mutableCopy];
|
|
332
|
-
}
|
|
333
|
-
else
|
|
334
|
-
{
|
|
335
|
-
_body = [[NSMutableData alloc] init];
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
- (void)dealloc
|
|
340
|
-
{
|
|
341
|
-
// ARC automatically releases all instance variables, but we include this
|
|
342
|
-
// for clarity and to match the pattern of the original CFNetwork implementation.
|
|
343
|
-
// All Objective-C objects (_headers, _body, _rawData, _version, _method, _url, _statusDescription)
|
|
344
|
-
// will be automatically released by ARC when this object is deallocated.
|
|
345
|
-
#if ! __has_feature(objc_arc)
|
|
346
|
-
[_headers release];
|
|
347
|
-
[_body release];
|
|
348
|
-
[_rawData release];
|
|
349
|
-
[_version release];
|
|
350
|
-
[_method release];
|
|
351
|
-
[_url release];
|
|
352
|
-
[_statusDescription release];
|
|
353
|
-
[super dealloc];
|
|
354
|
-
#endif
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
@end
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
#import <Foundation/Foundation.h>
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
@protocol HTTPResponse
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Returns the length of the data in bytes.
|
|
8
|
-
* If you don't know the length in advance, implement the isChunked method and have it return YES.
|
|
9
|
-
**/
|
|
10
|
-
- (UInt64)contentLength;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* The HTTP server supports range requests in order to allow things like
|
|
14
|
-
* file download resumption and optimized streaming on mobile devices.
|
|
15
|
-
**/
|
|
16
|
-
- (UInt64)offset;
|
|
17
|
-
- (void)setOffset:(UInt64)offset;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Returns the data for the response.
|
|
21
|
-
* You do not have to return data of the exact length that is given.
|
|
22
|
-
* You may optionally return data of a lesser length.
|
|
23
|
-
* However, you must never return data of a greater length than requested.
|
|
24
|
-
* Doing so could disrupt proper support for range requests.
|
|
25
|
-
*
|
|
26
|
-
* To support asynchronous responses, read the discussion at the bottom of this header.
|
|
27
|
-
**/
|
|
28
|
-
- (NSData *)readDataOfLength:(NSUInteger)length;
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Should only return YES after the HTTPConnection has read all available data.
|
|
32
|
-
* That is, all data for the response has been returned to the HTTPConnection via the readDataOfLength method.
|
|
33
|
-
**/
|
|
34
|
-
- (BOOL)isDone;
|
|
35
|
-
|
|
36
|
-
@optional
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* If you need time to calculate any part of the HTTP response headers (status code or header fields),
|
|
40
|
-
* this method allows you to delay sending the headers so that you may asynchronously execute the calculations.
|
|
41
|
-
* Simply implement this method and return YES until you have everything you need concerning the headers.
|
|
42
|
-
*
|
|
43
|
-
* This method ties into the asynchronous response architecture of the HTTPConnection.
|
|
44
|
-
* You should read the full discussion at the bottom of this header.
|
|
45
|
-
*
|
|
46
|
-
* If you return YES from this method,
|
|
47
|
-
* the HTTPConnection will wait for you to invoke the responseHasAvailableData method.
|
|
48
|
-
* After you do, the HTTPConnection will again invoke this method to see if the response is ready to send the headers.
|
|
49
|
-
*
|
|
50
|
-
* You should only delay sending the headers until you have everything you need concerning just the headers.
|
|
51
|
-
* Asynchronously generating the body of the response is not an excuse to delay sending the headers.
|
|
52
|
-
* Instead you should tie into the asynchronous response architecture, and use techniques such as the isChunked method.
|
|
53
|
-
*
|
|
54
|
-
* Important: You should read the discussion at the bottom of this header.
|
|
55
|
-
**/
|
|
56
|
-
- (BOOL)delayResponseHeaders;
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Status code for response.
|
|
60
|
-
* Allows for responses such as redirect (301), etc.
|
|
61
|
-
**/
|
|
62
|
-
- (NSInteger)status;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* If you want to add any extra HTTP headers to the response,
|
|
66
|
-
* simply return them in a dictionary in this method.
|
|
67
|
-
**/
|
|
68
|
-
- (NSDictionary *)httpHeaders;
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* If you don't know the content-length in advance,
|
|
72
|
-
* implement this method in your custom response class and return YES.
|
|
73
|
-
*
|
|
74
|
-
* Important: You should read the discussion at the bottom of this header.
|
|
75
|
-
**/
|
|
76
|
-
- (BOOL)isChunked;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* This method is called from the HTTPConnection class when the connection is closed,
|
|
80
|
-
* or when the connection is finished with the response.
|
|
81
|
-
* If your response is asynchronous, you should implement this method so you know not to
|
|
82
|
-
* invoke any methods on the HTTPConnection after this method is called (as the connection may be deallocated).
|
|
83
|
-
**/
|
|
84
|
-
- (void)connectionDidClose;
|
|
85
|
-
|
|
86
|
-
@end
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Important notice to those implementing custom asynchronous and/or chunked responses:
|
|
91
|
-
*
|
|
92
|
-
* HTTPConnection supports asynchronous responses. All you have to do in your custom response class is
|
|
93
|
-
* asynchronously generate the response, and invoke HTTPConnection's responseHasAvailableData method.
|
|
94
|
-
* You don't have to wait until you have all of the response ready to invoke this method. For example, if you
|
|
95
|
-
* generate the response in incremental chunks, you could call responseHasAvailableData after generating
|
|
96
|
-
* each chunk. Please see the HTTPAsyncFileResponse class for an example of how to do this.
|
|
97
|
-
*
|
|
98
|
-
* The normal flow of events for an HTTPConnection while responding to a request is like this:
|
|
99
|
-
* - Send http resopnse headers
|
|
100
|
-
* - Get data from response via readDataOfLength method.
|
|
101
|
-
* - Add data to asyncSocket's write queue.
|
|
102
|
-
* - Wait for asyncSocket to notify it that the data has been sent.
|
|
103
|
-
* - Get more data from response via readDataOfLength method.
|
|
104
|
-
* - ... continue this cycle until the entire response has been sent.
|
|
105
|
-
*
|
|
106
|
-
* With an asynchronous response, the flow is a little different.
|
|
107
|
-
*
|
|
108
|
-
* First the HTTPResponse is given the opportunity to postpone sending the HTTP response headers.
|
|
109
|
-
* This allows the response to asynchronously execute any code needed to calculate a part of the header.
|
|
110
|
-
* An example might be the response needs to generate some custom header fields,
|
|
111
|
-
* or perhaps the response needs to look for a resource on network-attached storage.
|
|
112
|
-
* Since the network-attached storage may be slow, the response doesn't know whether to send a 200 or 404 yet.
|
|
113
|
-
* In situations such as this, the HTTPResponse simply implements the delayResponseHeaders method and returns YES.
|
|
114
|
-
* After returning YES from this method, the HTTPConnection will wait until the response invokes its
|
|
115
|
-
* responseHasAvailableData method. After this occurs, the HTTPConnection will again query the delayResponseHeaders
|
|
116
|
-
* method to see if the response is ready to send the headers.
|
|
117
|
-
* This cycle will continue until the delayResponseHeaders method returns NO.
|
|
118
|
-
*
|
|
119
|
-
* You should only delay sending the response headers until you have everything you need concerning just the headers.
|
|
120
|
-
* Asynchronously generating the body of the response is not an excuse to delay sending the headers.
|
|
121
|
-
*
|
|
122
|
-
* After the response headers have been sent, the HTTPConnection calls your readDataOfLength method.
|
|
123
|
-
* You may or may not have any available data at this point. If you don't, then simply return nil.
|
|
124
|
-
* You should later invoke HTTPConnection's responseHasAvailableData when you have data to send.
|
|
125
|
-
*
|
|
126
|
-
* You don't have to keep track of when you return nil in the readDataOfLength method, or how many times you've invoked
|
|
127
|
-
* responseHasAvailableData. Just simply call responseHasAvailableData whenever you've generated new data, and
|
|
128
|
-
* return nil in your readDataOfLength whenever you don't have any available data in the requested range.
|
|
129
|
-
* HTTPConnection will automatically detect when it should be requesting new data and will act appropriately.
|
|
130
|
-
*
|
|
131
|
-
* It's important that you also keep in mind that the HTTP server supports range requests.
|
|
132
|
-
* The setOffset method is mandatory, and should not be ignored.
|
|
133
|
-
* Make sure you take into account the offset within the readDataOfLength method.
|
|
134
|
-
* You should also be aware that the HTTPConnection automatically sorts any range requests.
|
|
135
|
-
* So if your setOffset method is called with a value of 100, then you can safely release bytes 0-99.
|
|
136
|
-
*
|
|
137
|
-
* HTTPConnection can also help you keep your memory footprint small.
|
|
138
|
-
* Imagine you're dynamically generating a 10 MB response. You probably don't want to load all this data into
|
|
139
|
-
* RAM, and sit around waiting for HTTPConnection to slowly send it out over the network. All you need to do
|
|
140
|
-
* is pay attention to when HTTPConnection requests more data via readDataOfLength. This is because HTTPConnection
|
|
141
|
-
* will never allow asyncSocket's write queue to get much bigger than READ_CHUNKSIZE bytes. You should
|
|
142
|
-
* consider how you might be able to take advantage of this fact to generate your asynchronous response on demand,
|
|
143
|
-
* while at the same time keeping your memory footprint small, and your application lightning fast.
|
|
144
|
-
*
|
|
145
|
-
* If you don't know the content-length in advanced, you should also implement the isChunked method.
|
|
146
|
-
* This means the response will not include a Content-Length header, and will instead use "Transfer-Encoding: chunked".
|
|
147
|
-
* There's a good chance that if your response is asynchronous and dynamic, it's also chunked.
|
|
148
|
-
* If your response is chunked, you don't need to worry about range requests.
|
|
149
|
-
**/
|