mirror of
https://github.com/swisspol/GCDWebServer.git
synced 2026-02-11 00:00:07 +08:00
Compare commits
33 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea777865f3 | ||
|
|
5842149d4b | ||
|
|
46ee1a48d6 | ||
|
|
c1b2b79b06 | ||
|
|
41c56334d0 | ||
|
|
2810086816 | ||
|
|
c8cd771697 | ||
|
|
252c38c42a | ||
|
|
cedeb88cb6 | ||
|
|
854bbdc6b2 | ||
|
|
b949187770 | ||
|
|
dafcb0d895 | ||
|
|
7bceb8132a | ||
|
|
4c2ac12f7b | ||
|
|
1d2efbbbc7 | ||
|
|
91b832715a | ||
|
|
0852bf2d05 | ||
|
|
eb29232842 | ||
|
|
3b1fa05046 | ||
|
|
4535c5d61a | ||
|
|
ccd1eaa880 | ||
|
|
1b805c3951 | ||
|
|
2172872787 | ||
|
|
894eacd517 | ||
|
|
7a54bcbae5 | ||
|
|
a28ac82ba2 | ||
|
|
c062d9d6d3 | ||
|
|
bb32a721b6 | ||
|
|
1b6e4f6491 | ||
|
|
7b51023373 | ||
|
|
f21c6ab667 | ||
|
|
0dd6d8c5fc | ||
|
|
d58b2122ed |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
.DS_Store
|
||||
xcuserdata
|
||||
project.xcworkspace
|
||||
|
||||
Tests/Payload
|
||||
|
||||
2
.travis.yml
Normal file
2
.travis.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
language: objective-c
|
||||
script: ./Run-Tests.sh
|
||||
@@ -32,6 +32,8 @@
|
||||
|
||||
#import "GCDWebDAVServer.h"
|
||||
|
||||
#import "GCDWebServerFunctions.h"
|
||||
|
||||
#import "GCDWebServerDataRequest.h"
|
||||
#import "GCDWebServerFileRequest.h"
|
||||
|
||||
@@ -214,6 +216,15 @@ static inline BOOL _IsMacFinder(GCDWebServerRequest* request) {
|
||||
if (![[NSFileManager defaultManager] createDirectoryAtPath:absolutePath withIntermediateDirectories:NO attributes:nil error:&error]) {
|
||||
return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed creating directory \"%@\"", relativePath];
|
||||
}
|
||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||
NSString* creationDateHeader = [request.headers objectForKey:@"X-GCDWebServer-CreationDate"];
|
||||
if (creationDateHeader) {
|
||||
NSDate* date = GCDWebServerParseISO8601(creationDateHeader);
|
||||
if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate: date} ofItemAtPath:absolutePath error:&error]) {
|
||||
return [GCDWebServerErrorResponse responseWithServerError:kGCDWebServerHTTPStatusCode_InternalServerError underlyingError:error message:@"Failed setting creation date for directory \"%@\"", relativePath];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(davServer:didCreateDirectoryAtPath:)]) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
@@ -335,19 +346,11 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
||||
}
|
||||
|
||||
if ((properties & kDAVProperty_CreationDate) && [attributes objectForKey:NSFileCreationDate]) {
|
||||
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
|
||||
formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
|
||||
formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
|
||||
[xmlString appendFormat:@"<D:creationdate>%@</D:creationdate>", [formatter stringFromDate:[attributes fileCreationDate]]];
|
||||
[xmlString appendFormat:@"<D:creationdate>%@</D:creationdate>", GCDWebServerFormatISO8601([attributes fileCreationDate])];
|
||||
}
|
||||
|
||||
if ((properties & kDAVProperty_LastModified) && [attributes objectForKey:NSFileModificationDate]) {
|
||||
NSDateFormatter* formatter = [[NSDateFormatter alloc] init];
|
||||
formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
|
||||
formatter.timeZone = [NSTimeZone timeZoneWithName:@"GMT"];
|
||||
formatter.dateFormat = @"EEE', 'd' 'MMM' 'yyyy' 'HH:mm:ss' GMT'";
|
||||
[xmlString appendFormat:@"<D:getlastmodified>%@</D:getlastmodified>", [formatter stringFromDate:[attributes fileModificationDate]]];
|
||||
if ((properties & kDAVProperty_LastModified) && isFile && [attributes objectForKey:NSFileModificationDate]) { // Last modification date is not useful for directories as it changes implicitely and 'Last-Modified' header is not provided for directories anyway
|
||||
[xmlString appendFormat:@"<D:getlastmodified>%@</D:getlastmodified>", GCDWebServerFormatRFC822([attributes fileModificationDate])];
|
||||
}
|
||||
|
||||
if ((properties & kDAVProperty_ContentLength) && !isDirectory && [attributes objectForKey:NSFileSize]) {
|
||||
@@ -360,6 +363,8 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
||||
[xmlString appendString:@"</D:response>\n"];
|
||||
}
|
||||
CFRelease(escapedPath);
|
||||
} else {
|
||||
[self logError:@"Failed escaping path: %@", itemPath];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,10 +414,10 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
||||
}
|
||||
if (!success) {
|
||||
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding];
|
||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
|
||||
#if !__has_feature(objc_arc)
|
||||
[string release];
|
||||
[string autorelease];
|
||||
#endif
|
||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
|
||||
}
|
||||
} else {
|
||||
properties = kDAVAllProperties;
|
||||
@@ -510,10 +515,10 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
||||
}
|
||||
if (!success) {
|
||||
NSString* string = [[NSString alloc] initWithData:request.data encoding:NSUTF8StringEncoding];
|
||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
|
||||
#if !__has_feature(objc_arc)
|
||||
[string release];
|
||||
[string autorelease];
|
||||
#endif
|
||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_BadRequest message:@"Invalid DAV properties:\n%@", string];
|
||||
}
|
||||
|
||||
if (![scope isEqualToString:@"exclusive"] || ![type isEqualToString:@"write"] || ![depthHeader isEqualToString:@"0"]) {
|
||||
@@ -525,6 +530,12 @@ static inline xmlNodePtr _XMLChildWithName(xmlNodePtr child, const xmlChar* name
|
||||
return [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_Forbidden message:@"Locking item name \"%@\" is not allowed", itemName];
|
||||
}
|
||||
|
||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||
NSString* lockTokenHeader = [request.headers objectForKey:@"X-GCDWebServer-LockToken"];
|
||||
if (lockTokenHeader) {
|
||||
token = lockTokenHeader;
|
||||
}
|
||||
#endif
|
||||
if (!token) {
|
||||
CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault);
|
||||
CFStringRef string = CFUUIDCreateString(kCFAllocatorDefault, uuid);
|
||||
|
||||
47
GCDWebServer.podspec
Normal file
47
GCDWebServer.podspec
Normal file
@@ -0,0 +1,47 @@
|
||||
# http://guides.cocoapods.org/syntax/podspec.html
|
||||
# Verify Podspec with:
|
||||
# sudo gem update cocoapods
|
||||
# pod spec lint GCDWebServer.podspec --verbose
|
||||
# Add to source line:
|
||||
# :tag => s.version.to_s
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'GCDWebServer'
|
||||
s.version = '2.1.1'
|
||||
s.author = { 'Pierre-Olivier Latour' => 'info@pol-online.net' }
|
||||
s.license = { :type => 'BSD', :file => 'LICENSE' }
|
||||
s.homepage = 'https://github.com/swisspol/GCDWebServer'
|
||||
s.summary = 'Lightweight GCD based HTTP server for OS X & iOS (includes web based uploader & WebDAV server)'
|
||||
|
||||
s.source = { :git => 'https://github.com/swisspol/GCDWebServer.git' }
|
||||
s.ios.deployment_target = '5.0'
|
||||
s.osx.deployment_target = '10.7'
|
||||
s.requires_arc = true
|
||||
|
||||
s.default_subspec = 'Core'
|
||||
|
||||
s.subspec 'Core' do |cs|
|
||||
cs.source_files = 'GCDWebServer/**/*.{h,m}'
|
||||
cs.requires_arc = true
|
||||
cs.ios.library = 'z'
|
||||
cs.osx.library = 'z'
|
||||
cs.compiler_flags = '-DNDEBUG' # TODO: Only set this for Release configuration
|
||||
end
|
||||
|
||||
s.subspec 'WebDAV' do |cs|
|
||||
cs.dependency 'GCDWebServer/Core'
|
||||
cs.source_files = 'GCDWebDAVServer/*.{h,m}'
|
||||
cs.requires_arc = true
|
||||
cs.ios.library = 'xml2'
|
||||
cs.osx.library = 'xml2'
|
||||
cs.compiler_flags = '-I$(SDKROOT)/usr/include/libxml2'
|
||||
end
|
||||
|
||||
s.subspec 'WebUploader' do |cs|
|
||||
cs.dependency 'GCDWebServer/Core'
|
||||
cs.source_files = 'GCDWebUploader/*.{h,m}'
|
||||
cs.requires_arc = true
|
||||
cs.resource = "GCDWebUploader/GCDWebUploader.bundle"
|
||||
end
|
||||
|
||||
end
|
||||
@@ -24,36 +24,38 @@
|
||||
/* Begin PBXBuildFile section */
|
||||
E208D149167B76B700500836 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E208D148167B76B700500836 /* CFNetwork.framework */; };
|
||||
E208D1B3167BB17E00500836 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E208D1B2167BB17E00500836 /* CoreServices.framework */; };
|
||||
E22112851690B63A0048D2B2 /* GCDWebServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E221127D1690B63A0048D2B2 /* GCDWebServer.m */; };
|
||||
E22112861690B63A0048D2B2 /* GCDWebServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E221127D1690B63A0048D2B2 /* GCDWebServer.m */; };
|
||||
E22112871690B63A0048D2B2 /* GCDWebServerConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = E221127F1690B63A0048D2B2 /* GCDWebServerConnection.m */; };
|
||||
E22112881690B63A0048D2B2 /* GCDWebServerConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = E221127F1690B63A0048D2B2 /* GCDWebServerConnection.m */; };
|
||||
E22112891690B63A0048D2B2 /* GCDWebServerRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112821690B63A0048D2B2 /* GCDWebServerRequest.m */; };
|
||||
E221128A1690B63A0048D2B2 /* GCDWebServerRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112821690B63A0048D2B2 /* GCDWebServerRequest.m */; };
|
||||
E221128B1690B63A0048D2B2 /* GCDWebServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112841690B63A0048D2B2 /* GCDWebServerResponse.m */; };
|
||||
E221128C1690B63A0048D2B2 /* GCDWebServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112841690B63A0048D2B2 /* GCDWebServerResponse.m */; };
|
||||
E221128F1690B6470048D2B2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E221128E1690B6470048D2B2 /* main.m */; };
|
||||
E22112951690B64F0048D2B2 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112921690B64F0048D2B2 /* AppDelegate.m */; };
|
||||
E22112971690B64F0048D2B2 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E22112941690B64F0048D2B2 /* main.m */; };
|
||||
E22112991690B7AA0048D2B2 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E22112981690B7AA0048D2B2 /* CFNetwork.framework */; };
|
||||
E221129B1690B7B10048D2B2 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E221129A1690B7B10048D2B2 /* UIKit.framework */; };
|
||||
E221129D1690B7BA0048D2B2 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E221129C1690B7BA0048D2B2 /* MobileCoreServices.framework */; };
|
||||
E276647C18F3BC2100A034BA /* GCDWebServerErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E276647B18F3BC2100A034BA /* GCDWebServerErrorResponse.m */; };
|
||||
E276647D18F3BC2100A034BA /* GCDWebServerErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E276647B18F3BC2100A034BA /* GCDWebServerErrorResponse.m */; };
|
||||
E2A0E7ED18F1D03700C580B1 /* GCDWebServerDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7EC18F1D03700C580B1 /* GCDWebServerDataResponse.m */; };
|
||||
E2A0E7EE18F1D03700C580B1 /* GCDWebServerDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7EC18F1D03700C580B1 /* GCDWebServerDataResponse.m */; };
|
||||
E2A0E7F118F1D12E00C580B1 /* GCDWebServerFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F018F1D12E00C580B1 /* GCDWebServerFileResponse.m */; };
|
||||
E2A0E7F218F1D12E00C580B1 /* GCDWebServerFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F018F1D12E00C580B1 /* GCDWebServerFileResponse.m */; };
|
||||
E2A0E7F518F1D1E500C580B1 /* GCDWebServerStreamingResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F418F1D1E500C580B1 /* GCDWebServerStreamingResponse.m */; };
|
||||
E2A0E7F618F1D1E500C580B1 /* GCDWebServerStreamingResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F418F1D1E500C580B1 /* GCDWebServerStreamingResponse.m */; };
|
||||
E2A0E7F918F1D24700C580B1 /* GCDWebServerDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F818F1D24700C580B1 /* GCDWebServerDataRequest.m */; };
|
||||
E2A0E7FA18F1D24700C580B1 /* GCDWebServerDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7F818F1D24700C580B1 /* GCDWebServerDataRequest.m */; };
|
||||
E2A0E7FD18F1D36C00C580B1 /* GCDWebServerFileRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7FC18F1D36C00C580B1 /* GCDWebServerFileRequest.m */; };
|
||||
E2A0E7FE18F1D36C00C580B1 /* GCDWebServerFileRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E7FC18F1D36C00C580B1 /* GCDWebServerFileRequest.m */; };
|
||||
E2A0E80118F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80018F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m */; };
|
||||
E2A0E80218F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80018F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m */; };
|
||||
E2A0E80518F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80418F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m */; };
|
||||
E2A0E80618F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80418F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m */; };
|
||||
E28BAE3418F99C810095C089 /* GCDWebServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1718F99C810095C089 /* GCDWebServer.m */; };
|
||||
E28BAE3518F99C810095C089 /* GCDWebServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1718F99C810095C089 /* GCDWebServer.m */; };
|
||||
E28BAE3618F99C810095C089 /* GCDWebServerConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1918F99C810095C089 /* GCDWebServerConnection.m */; };
|
||||
E28BAE3718F99C810095C089 /* GCDWebServerConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1918F99C810095C089 /* GCDWebServerConnection.m */; };
|
||||
E28BAE3818F99C810095C089 /* GCDWebServerFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1B18F99C810095C089 /* GCDWebServerFunctions.m */; };
|
||||
E28BAE3918F99C810095C089 /* GCDWebServerFunctions.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1B18F99C810095C089 /* GCDWebServerFunctions.m */; };
|
||||
E28BAE3A18F99C810095C089 /* GCDWebServerRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1F18F99C810095C089 /* GCDWebServerRequest.m */; };
|
||||
E28BAE3B18F99C810095C089 /* GCDWebServerRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE1F18F99C810095C089 /* GCDWebServerRequest.m */; };
|
||||
E28BAE3C18F99C810095C089 /* GCDWebServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2118F99C810095C089 /* GCDWebServerResponse.m */; };
|
||||
E28BAE3D18F99C810095C089 /* GCDWebServerResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2118F99C810095C089 /* GCDWebServerResponse.m */; };
|
||||
E28BAE3E18F99C810095C089 /* GCDWebServerDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2418F99C810095C089 /* GCDWebServerDataRequest.m */; };
|
||||
E28BAE3F18F99C810095C089 /* GCDWebServerDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2418F99C810095C089 /* GCDWebServerDataRequest.m */; };
|
||||
E28BAE4018F99C810095C089 /* GCDWebServerFileRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2618F99C810095C089 /* GCDWebServerFileRequest.m */; };
|
||||
E28BAE4118F99C810095C089 /* GCDWebServerFileRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2618F99C810095C089 /* GCDWebServerFileRequest.m */; };
|
||||
E28BAE4218F99C810095C089 /* GCDWebServerMultiPartFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2818F99C810095C089 /* GCDWebServerMultiPartFormRequest.m */; };
|
||||
E28BAE4318F99C810095C089 /* GCDWebServerMultiPartFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2818F99C810095C089 /* GCDWebServerMultiPartFormRequest.m */; };
|
||||
E28BAE4418F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2A18F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m */; };
|
||||
E28BAE4518F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2A18F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m */; };
|
||||
E28BAE4618F99C810095C089 /* GCDWebServerDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2D18F99C810095C089 /* GCDWebServerDataResponse.m */; };
|
||||
E28BAE4718F99C810095C089 /* GCDWebServerDataResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2D18F99C810095C089 /* GCDWebServerDataResponse.m */; };
|
||||
E28BAE4818F99C810095C089 /* GCDWebServerErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2F18F99C810095C089 /* GCDWebServerErrorResponse.m */; };
|
||||
E28BAE4918F99C810095C089 /* GCDWebServerErrorResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE2F18F99C810095C089 /* GCDWebServerErrorResponse.m */; };
|
||||
E28BAE4A18F99C810095C089 /* GCDWebServerFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE3118F99C810095C089 /* GCDWebServerFileResponse.m */; };
|
||||
E28BAE4B18F99C810095C089 /* GCDWebServerFileResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE3118F99C810095C089 /* GCDWebServerFileResponse.m */; };
|
||||
E28BAE4C18F99C810095C089 /* GCDWebServerStreamingResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE3318F99C810095C089 /* GCDWebServerStreamingResponse.m */; };
|
||||
E28BAE4D18F99C810095C089 /* GCDWebServerStreamingResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = E28BAE3318F99C810095C089 /* GCDWebServerStreamingResponse.m */; };
|
||||
E2A0E80A18F3432600C580B1 /* GCDWebDAVServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80918F3432600C580B1 /* GCDWebDAVServer.m */; };
|
||||
E2A0E80B18F3432600C580B1 /* GCDWebDAVServer.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A0E80918F3432600C580B1 /* GCDWebDAVServer.m */; };
|
||||
E2A0E80D18F35C9A00C580B1 /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A0E80C18F35C9A00C580B1 /* libxml2.dylib */; };
|
||||
@@ -102,15 +104,6 @@
|
||||
E208D148167B76B700500836 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
|
||||
E208D1B2167BB17E00500836 /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
|
||||
E221125A1690B4DE0048D2B2 /* GCDWebServer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GCDWebServer.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
E221127C1690B63A0048D2B2 /* GCDWebServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServer.h; sourceTree = "<group>"; };
|
||||
E221127D1690B63A0048D2B2 /* GCDWebServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServer.m; sourceTree = "<group>"; };
|
||||
E221127E1690B63A0048D2B2 /* GCDWebServerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerConnection.h; sourceTree = "<group>"; };
|
||||
E221127F1690B63A0048D2B2 /* GCDWebServerConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerConnection.m; sourceTree = "<group>"; };
|
||||
E22112801690B63A0048D2B2 /* GCDWebServerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerPrivate.h; sourceTree = "<group>"; };
|
||||
E22112811690B63A0048D2B2 /* GCDWebServerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerRequest.h; sourceTree = "<group>"; };
|
||||
E22112821690B63A0048D2B2 /* GCDWebServerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerRequest.m; sourceTree = "<group>"; };
|
||||
E22112831690B63A0048D2B2 /* GCDWebServerResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerResponse.h; sourceTree = "<group>"; };
|
||||
E22112841690B63A0048D2B2 /* GCDWebServerResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerResponse.m; sourceTree = "<group>"; };
|
||||
E221128E1690B6470048D2B2 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||
E22112911690B64F0048D2B2 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
E22112921690B64F0048D2B2 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||
@@ -119,27 +112,38 @@
|
||||
E22112981690B7AA0048D2B2 /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/CFNetwork.framework; sourceTree = DEVELOPER_DIR; };
|
||||
E221129A1690B7B10048D2B2 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
|
||||
E221129C1690B7BA0048D2B2 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS6.0.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; };
|
||||
E276647A18F3BC2100A034BA /* GCDWebServerErrorResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerErrorResponse.h; sourceTree = "<group>"; };
|
||||
E276647B18F3BC2100A034BA /* GCDWebServerErrorResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerErrorResponse.m; sourceTree = "<group>"; };
|
||||
E2A0E7EB18F1D03700C580B1 /* GCDWebServerDataResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerDataResponse.h; sourceTree = "<group>"; };
|
||||
E2A0E7EC18F1D03700C580B1 /* GCDWebServerDataResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerDataResponse.m; sourceTree = "<group>"; };
|
||||
E2A0E7EF18F1D12E00C580B1 /* GCDWebServerFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerFileResponse.h; sourceTree = "<group>"; };
|
||||
E2A0E7F018F1D12E00C580B1 /* GCDWebServerFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerFileResponse.m; sourceTree = "<group>"; };
|
||||
E2A0E7F318F1D1E500C580B1 /* GCDWebServerStreamingResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerStreamingResponse.h; sourceTree = "<group>"; };
|
||||
E2A0E7F418F1D1E500C580B1 /* GCDWebServerStreamingResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerStreamingResponse.m; sourceTree = "<group>"; };
|
||||
E2A0E7F718F1D24700C580B1 /* GCDWebServerDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerDataRequest.h; sourceTree = "<group>"; };
|
||||
E2A0E7F818F1D24700C580B1 /* GCDWebServerDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerDataRequest.m; sourceTree = "<group>"; };
|
||||
E2A0E7FB18F1D36C00C580B1 /* GCDWebServerFileRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerFileRequest.h; sourceTree = "<group>"; };
|
||||
E2A0E7FC18F1D36C00C580B1 /* GCDWebServerFileRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerFileRequest.m; sourceTree = "<group>"; };
|
||||
E2A0E7FF18F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerMultiPartFormRequest.h; sourceTree = "<group>"; };
|
||||
E2A0E80018F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerMultiPartFormRequest.m; sourceTree = "<group>"; };
|
||||
E2A0E80318F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerURLEncodedFormRequest.h; sourceTree = "<group>"; };
|
||||
E2A0E80418F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerURLEncodedFormRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE1618F99C810095C089 /* GCDWebServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServer.h; sourceTree = "<group>"; };
|
||||
E28BAE1718F99C810095C089 /* GCDWebServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServer.m; sourceTree = "<group>"; };
|
||||
E28BAE1818F99C810095C089 /* GCDWebServerConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerConnection.h; sourceTree = "<group>"; };
|
||||
E28BAE1918F99C810095C089 /* GCDWebServerConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerConnection.m; sourceTree = "<group>"; };
|
||||
E28BAE1A18F99C810095C089 /* GCDWebServerFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerFunctions.h; sourceTree = "<group>"; };
|
||||
E28BAE1B18F99C810095C089 /* GCDWebServerFunctions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerFunctions.m; sourceTree = "<group>"; };
|
||||
E28BAE1C18F99C810095C089 /* GCDWebServerHTTPStatusCodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerHTTPStatusCodes.h; sourceTree = "<group>"; };
|
||||
E28BAE1D18F99C810095C089 /* GCDWebServerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerPrivate.h; sourceTree = "<group>"; };
|
||||
E28BAE1E18F99C810095C089 /* GCDWebServerRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerRequest.h; sourceTree = "<group>"; };
|
||||
E28BAE1F18F99C810095C089 /* GCDWebServerRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE2018F99C810095C089 /* GCDWebServerResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerResponse.h; sourceTree = "<group>"; };
|
||||
E28BAE2118F99C810095C089 /* GCDWebServerResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerResponse.m; sourceTree = "<group>"; };
|
||||
E28BAE2318F99C810095C089 /* GCDWebServerDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerDataRequest.h; sourceTree = "<group>"; };
|
||||
E28BAE2418F99C810095C089 /* GCDWebServerDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerDataRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE2518F99C810095C089 /* GCDWebServerFileRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerFileRequest.h; sourceTree = "<group>"; };
|
||||
E28BAE2618F99C810095C089 /* GCDWebServerFileRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerFileRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE2718F99C810095C089 /* GCDWebServerMultiPartFormRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerMultiPartFormRequest.h; sourceTree = "<group>"; };
|
||||
E28BAE2818F99C810095C089 /* GCDWebServerMultiPartFormRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerMultiPartFormRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE2918F99C810095C089 /* GCDWebServerURLEncodedFormRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerURLEncodedFormRequest.h; sourceTree = "<group>"; };
|
||||
E28BAE2A18F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerURLEncodedFormRequest.m; sourceTree = "<group>"; };
|
||||
E28BAE2C18F99C810095C089 /* GCDWebServerDataResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerDataResponse.h; sourceTree = "<group>"; };
|
||||
E28BAE2D18F99C810095C089 /* GCDWebServerDataResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerDataResponse.m; sourceTree = "<group>"; };
|
||||
E28BAE2E18F99C810095C089 /* GCDWebServerErrorResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerErrorResponse.h; sourceTree = "<group>"; };
|
||||
E28BAE2F18F99C810095C089 /* GCDWebServerErrorResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerErrorResponse.m; sourceTree = "<group>"; };
|
||||
E28BAE3018F99C810095C089 /* GCDWebServerFileResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerFileResponse.h; sourceTree = "<group>"; };
|
||||
E28BAE3118F99C810095C089 /* GCDWebServerFileResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerFileResponse.m; sourceTree = "<group>"; };
|
||||
E28BAE3218F99C810095C089 /* GCDWebServerStreamingResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebServerStreamingResponse.h; sourceTree = "<group>"; };
|
||||
E28BAE3318F99C810095C089 /* GCDWebServerStreamingResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebServerStreamingResponse.m; sourceTree = "<group>"; };
|
||||
E2A0E80818F3432600C580B1 /* GCDWebDAVServer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCDWebDAVServer.h; sourceTree = "<group>"; };
|
||||
E2A0E80918F3432600C580B1 /* GCDWebDAVServer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GCDWebDAVServer.m; sourceTree = "<group>"; };
|
||||
E2A0E80C18F35C9A00C580B1 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/usr/lib/libxml2.dylib; sourceTree = DEVELOPER_DIR; };
|
||||
E2A0E80E18F35CA300C580B1 /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
|
||||
E2A0E81018F3737B00C580B1 /* GCDWebServerHTTPStatusCodes.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GCDWebServerHTTPStatusCodes.h; sourceTree = "<group>"; };
|
||||
E2B0D4A618F13495009A7927 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
E2B0D4A818F134A8009A7927 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.1.sdk/usr/lib/libz.dylib; sourceTree = DEVELOPER_DIR; };
|
||||
E2BE850718E77ECA0061360B /* GCDWebUploader.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = GCDWebUploader.bundle; sourceTree = "<group>"; };
|
||||
@@ -179,7 +183,7 @@
|
||||
08FB7794FE84155DC02AAC07 /* LittleCMS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E221127B1690B63A0048D2B2 /* CGDWebServer */,
|
||||
E28BAE1418F99C810095C089 /* GCDWebServer */,
|
||||
E2A0E80718F3432600C580B1 /* GCDWebDAVServer */,
|
||||
E2BE850618E77ECA0061360B /* GCDWebUploader */,
|
||||
E221128D1690B6470048D2B2 /* Mac */,
|
||||
@@ -200,39 +204,6 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E221127B1690B63A0048D2B2 /* CGDWebServer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E221127C1690B63A0048D2B2 /* GCDWebServer.h */,
|
||||
E221127D1690B63A0048D2B2 /* GCDWebServer.m */,
|
||||
E221127E1690B63A0048D2B2 /* GCDWebServerConnection.h */,
|
||||
E221127F1690B63A0048D2B2 /* GCDWebServerConnection.m */,
|
||||
E2A0E7F718F1D24700C580B1 /* GCDWebServerDataRequest.h */,
|
||||
E2A0E7F818F1D24700C580B1 /* GCDWebServerDataRequest.m */,
|
||||
E2A0E7EB18F1D03700C580B1 /* GCDWebServerDataResponse.h */,
|
||||
E2A0E7EC18F1D03700C580B1 /* GCDWebServerDataResponse.m */,
|
||||
E276647A18F3BC2100A034BA /* GCDWebServerErrorResponse.h */,
|
||||
E276647B18F3BC2100A034BA /* GCDWebServerErrorResponse.m */,
|
||||
E2A0E7FB18F1D36C00C580B1 /* GCDWebServerFileRequest.h */,
|
||||
E2A0E7FC18F1D36C00C580B1 /* GCDWebServerFileRequest.m */,
|
||||
E2A0E7EF18F1D12E00C580B1 /* GCDWebServerFileResponse.h */,
|
||||
E2A0E7F018F1D12E00C580B1 /* GCDWebServerFileResponse.m */,
|
||||
E2A0E81018F3737B00C580B1 /* GCDWebServerHTTPStatusCodes.h */,
|
||||
E2A0E7FF18F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.h */,
|
||||
E2A0E80018F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m */,
|
||||
E22112801690B63A0048D2B2 /* GCDWebServerPrivate.h */,
|
||||
E22112811690B63A0048D2B2 /* GCDWebServerRequest.h */,
|
||||
E22112821690B63A0048D2B2 /* GCDWebServerRequest.m */,
|
||||
E22112831690B63A0048D2B2 /* GCDWebServerResponse.h */,
|
||||
E22112841690B63A0048D2B2 /* GCDWebServerResponse.m */,
|
||||
E2A0E7F318F1D1E500C580B1 /* GCDWebServerStreamingResponse.h */,
|
||||
E2A0E7F418F1D1E500C580B1 /* GCDWebServerStreamingResponse.m */,
|
||||
E2A0E80318F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.h */,
|
||||
E2A0E80418F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m */,
|
||||
);
|
||||
path = CGDWebServer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E221128D1690B6470048D2B2 /* Mac */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -276,6 +247,65 @@
|
||||
name = "Mac Frameworks and Libraries";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E28BAE1418F99C810095C089 /* GCDWebServer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E28BAE1518F99C810095C089 /* Core */,
|
||||
E28BAE2218F99C810095C089 /* Requests */,
|
||||
E28BAE2B18F99C810095C089 /* Responses */,
|
||||
);
|
||||
path = GCDWebServer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E28BAE1518F99C810095C089 /* Core */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E28BAE1618F99C810095C089 /* GCDWebServer.h */,
|
||||
E28BAE1718F99C810095C089 /* GCDWebServer.m */,
|
||||
E28BAE1818F99C810095C089 /* GCDWebServerConnection.h */,
|
||||
E28BAE1918F99C810095C089 /* GCDWebServerConnection.m */,
|
||||
E28BAE1A18F99C810095C089 /* GCDWebServerFunctions.h */,
|
||||
E28BAE1B18F99C810095C089 /* GCDWebServerFunctions.m */,
|
||||
E28BAE1C18F99C810095C089 /* GCDWebServerHTTPStatusCodes.h */,
|
||||
E28BAE1D18F99C810095C089 /* GCDWebServerPrivate.h */,
|
||||
E28BAE1E18F99C810095C089 /* GCDWebServerRequest.h */,
|
||||
E28BAE1F18F99C810095C089 /* GCDWebServerRequest.m */,
|
||||
E28BAE2018F99C810095C089 /* GCDWebServerResponse.h */,
|
||||
E28BAE2118F99C810095C089 /* GCDWebServerResponse.m */,
|
||||
);
|
||||
path = Core;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E28BAE2218F99C810095C089 /* Requests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E28BAE2318F99C810095C089 /* GCDWebServerDataRequest.h */,
|
||||
E28BAE2418F99C810095C089 /* GCDWebServerDataRequest.m */,
|
||||
E28BAE2518F99C810095C089 /* GCDWebServerFileRequest.h */,
|
||||
E28BAE2618F99C810095C089 /* GCDWebServerFileRequest.m */,
|
||||
E28BAE2718F99C810095C089 /* GCDWebServerMultiPartFormRequest.h */,
|
||||
E28BAE2818F99C810095C089 /* GCDWebServerMultiPartFormRequest.m */,
|
||||
E28BAE2918F99C810095C089 /* GCDWebServerURLEncodedFormRequest.h */,
|
||||
E28BAE2A18F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m */,
|
||||
);
|
||||
path = Requests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E28BAE2B18F99C810095C089 /* Responses */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E28BAE2C18F99C810095C089 /* GCDWebServerDataResponse.h */,
|
||||
E28BAE2D18F99C810095C089 /* GCDWebServerDataResponse.m */,
|
||||
E28BAE2E18F99C810095C089 /* GCDWebServerErrorResponse.h */,
|
||||
E28BAE2F18F99C810095C089 /* GCDWebServerErrorResponse.m */,
|
||||
E28BAE3018F99C810095C089 /* GCDWebServerFileResponse.h */,
|
||||
E28BAE3118F99C810095C089 /* GCDWebServerFileResponse.m */,
|
||||
E28BAE3218F99C810095C089 /* GCDWebServerStreamingResponse.h */,
|
||||
E28BAE3318F99C810095C089 /* GCDWebServerStreamingResponse.m */,
|
||||
);
|
||||
path = Responses;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E2A0E80718F3432600C580B1 /* GCDWebDAVServer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -302,6 +332,7 @@
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "GCDWebServer (Mac)" */;
|
||||
buildPhases = (
|
||||
E21F038418FB37D80043AD1E /* Delete GCDWebUploader.bundle */,
|
||||
E2BE850E18E788910061360B /* CopyFiles */,
|
||||
8DD76FAB0486AB0100D96B5E /* Sources */,
|
||||
8DD76FAD0486AB0100D96B5E /* Frameworks */,
|
||||
@@ -374,26 +405,45 @@
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
E21F038418FB37D80043AD1E /* Delete GCDWebUploader.bundle */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Delete GCDWebUploader.bundle";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "cd \"$BUILT_PRODUCTS_DIR\"\nrm -rf \"GCDWebUploader.bundle\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
8DD76FAB0486AB0100D96B5E /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E22112851690B63A0048D2B2 /* GCDWebServer.m in Sources */,
|
||||
E2A0E7FD18F1D36C00C580B1 /* GCDWebServerFileRequest.m in Sources */,
|
||||
E22112871690B63A0048D2B2 /* GCDWebServerConnection.m in Sources */,
|
||||
E2A0E80518F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m in Sources */,
|
||||
E2A0E7F918F1D24700C580B1 /* GCDWebServerDataRequest.m in Sources */,
|
||||
E22112891690B63A0048D2B2 /* GCDWebServerRequest.m in Sources */,
|
||||
E276647C18F3BC2100A034BA /* GCDWebServerErrorResponse.m in Sources */,
|
||||
E2A0E7ED18F1D03700C580B1 /* GCDWebServerDataResponse.m in Sources */,
|
||||
E2A0E7F518F1D1E500C580B1 /* GCDWebServerStreamingResponse.m in Sources */,
|
||||
E2A0E80118F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m in Sources */,
|
||||
E221128B1690B63A0048D2B2 /* GCDWebServerResponse.m in Sources */,
|
||||
E28BAE4618F99C810095C089 /* GCDWebServerDataResponse.m in Sources */,
|
||||
E28BAE3818F99C810095C089 /* GCDWebServerFunctions.m in Sources */,
|
||||
E28BAE4A18F99C810095C089 /* GCDWebServerFileResponse.m in Sources */,
|
||||
E28BAE4418F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m in Sources */,
|
||||
E28BAE3A18F99C810095C089 /* GCDWebServerRequest.m in Sources */,
|
||||
E28BAE3418F99C810095C089 /* GCDWebServer.m in Sources */,
|
||||
E28BAE3618F99C810095C089 /* GCDWebServerConnection.m in Sources */,
|
||||
E28BAE3C18F99C810095C089 /* GCDWebServerResponse.m in Sources */,
|
||||
E28BAE4018F99C810095C089 /* GCDWebServerFileRequest.m in Sources */,
|
||||
E28BAE4C18F99C810095C089 /* GCDWebServerStreamingResponse.m in Sources */,
|
||||
E28BAE3E18F99C810095C089 /* GCDWebServerDataRequest.m in Sources */,
|
||||
E2A0E80A18F3432600C580B1 /* GCDWebDAVServer.m in Sources */,
|
||||
E28BAE4218F99C810095C089 /* GCDWebServerMultiPartFormRequest.m in Sources */,
|
||||
E2BE850C18E785940061360B /* GCDWebUploader.m in Sources */,
|
||||
E221128F1690B6470048D2B2 /* main.m in Sources */,
|
||||
E2A0E7F118F1D12E00C580B1 /* GCDWebServerFileResponse.m in Sources */,
|
||||
E28BAE4818F99C810095C089 /* GCDWebServerErrorResponse.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -402,21 +452,22 @@
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E2A0E80B18F3432600C580B1 /* GCDWebDAVServer.m in Sources */,
|
||||
E22112861690B63A0048D2B2 /* GCDWebServer.m in Sources */,
|
||||
E276647D18F3BC2100A034BA /* GCDWebServerErrorResponse.m in Sources */,
|
||||
E2A0E7EE18F1D03700C580B1 /* GCDWebServerDataResponse.m in Sources */,
|
||||
E2A0E80218F1D3DE00C580B1 /* GCDWebServerMultiPartFormRequest.m in Sources */,
|
||||
E22112881690B63A0048D2B2 /* GCDWebServerConnection.m in Sources */,
|
||||
E221128A1690B63A0048D2B2 /* GCDWebServerRequest.m in Sources */,
|
||||
E221128C1690B63A0048D2B2 /* GCDWebServerResponse.m in Sources */,
|
||||
E2A0E7FA18F1D24700C580B1 /* GCDWebServerDataRequest.m in Sources */,
|
||||
E2A0E80618F1D4A700C580B1 /* GCDWebServerURLEncodedFormRequest.m in Sources */,
|
||||
E28BAE4918F99C810095C089 /* GCDWebServerErrorResponse.m in Sources */,
|
||||
E28BAE4518F99C810095C089 /* GCDWebServerURLEncodedFormRequest.m in Sources */,
|
||||
E28BAE4B18F99C810095C089 /* GCDWebServerFileResponse.m in Sources */,
|
||||
E28BAE3918F99C810095C089 /* GCDWebServerFunctions.m in Sources */,
|
||||
E28BAE4118F99C810095C089 /* GCDWebServerFileRequest.m in Sources */,
|
||||
E28BAE4D18F99C810095C089 /* GCDWebServerStreamingResponse.m in Sources */,
|
||||
E28BAE3F18F99C810095C089 /* GCDWebServerDataRequest.m in Sources */,
|
||||
E2BE850B18E77ECA0061360B /* GCDWebUploader.m in Sources */,
|
||||
E22112951690B64F0048D2B2 /* AppDelegate.m in Sources */,
|
||||
E2A0E7FE18F1D36C00C580B1 /* GCDWebServerFileRequest.m in Sources */,
|
||||
E2A0E7F618F1D1E500C580B1 /* GCDWebServerStreamingResponse.m in Sources */,
|
||||
E2A0E7F218F1D12E00C580B1 /* GCDWebServerFileResponse.m in Sources */,
|
||||
E28BAE4718F99C810095C089 /* GCDWebServerDataResponse.m in Sources */,
|
||||
E28BAE3D18F99C810095C089 /* GCDWebServerResponse.m in Sources */,
|
||||
E28BAE3518F99C810095C089 /* GCDWebServer.m in Sources */,
|
||||
E28BAE3718F99C810095C089 /* GCDWebServerConnection.m in Sources */,
|
||||
E28BAE3B18F99C810095C089 /* GCDWebServerRequest.m in Sources */,
|
||||
E22112971690B64F0048D2B2 /* main.m in Sources */,
|
||||
E28BAE4318F99C810095C089 /* GCDWebServerMultiPartFormRequest.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -461,6 +512,7 @@
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = __GCDWEBSERVER_ENABLE_TESTING__;
|
||||
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
WARNING_CFLAGS = (
|
||||
@@ -488,6 +540,7 @@
|
||||
buildSettings = {
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = NDEBUG;
|
||||
GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS = __GCDWEBSERVER_ENABLE_TESTING__;
|
||||
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
|
||||
HEADER_SEARCH_PATHS = "$(SDKROOT)/usr/include/libxml2";
|
||||
WARNING_CFLAGS = "-Wall";
|
||||
|
||||
@@ -42,20 +42,6 @@ typedef NS_ENUM(int, GCDWebServerLogLevel) {
|
||||
typedef GCDWebServerRequest* (^GCDWebServerMatchBlock)(NSString* requestMethod, NSURL* requestURL, NSDictionary* requestHeaders, NSString* urlPath, NSDictionary* urlQuery);
|
||||
typedef GCDWebServerResponse* (^GCDWebServerProcessBlock)(GCDWebServerRequest* request);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension);
|
||||
NSString* GCDWebServerEscapeURLString(NSString* string);
|
||||
NSString* GCDWebServerUnescapeURLString(NSString* string);
|
||||
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
|
||||
NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of primary connected service on OS X or of WiFi interface on iOS if connected
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@interface GCDWebServer : NSObject
|
||||
@property(nonatomic, readonly, getter=isRunning) BOOL running;
|
||||
@property(nonatomic, readonly) NSUInteger port;
|
||||
@@ -79,8 +65,12 @@ NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of prima
|
||||
@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
|
||||
#if !TARGET_OS_IPHONE
|
||||
@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)
|
||||
- (BOOL)runWithPort:(NSUInteger)port; // Starts then automatically stops on SIGINT i.e. Ctrl-C (use on main thread only)
|
||||
#endif
|
||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||
- (NSInteger)runTestsInDirectory:(NSString*)path withPort:(NSUInteger)port; // Returns number of failed tests or -1 if server failed to start
|
||||
#endif
|
||||
@end
|
||||
|
||||
@interface GCDWebServer (Handlers)
|
||||
@@ -26,16 +26,7 @@
|
||||
*/
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#else
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#endif
|
||||
|
||||
#import <netinet/in.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <net/if.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import "GCDWebServerPrivate.h"
|
||||
|
||||
@@ -53,6 +44,9 @@
|
||||
NSUInteger _port;
|
||||
dispatch_source_t _source;
|
||||
CFNetServiceRef _service;
|
||||
#if !TARGET_OS_IPHONE
|
||||
BOOL _recording;
|
||||
#endif
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -71,8 +65,6 @@ GCDWebServerLogLevel GCDLogLevel = kGCDWebServerLogLevel_Debug;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static NSDateFormatter* _dateFormatterRFC822 = nil;
|
||||
static dispatch_queue_t _dateFormatterQueue = NULL;
|
||||
#if !TARGET_OS_IPHONE
|
||||
static BOOL _run;
|
||||
#endif
|
||||
@@ -91,187 +83,6 @@ void GCDLogMessage(GCDWebServerLogLevel level, NSString* format, ...) {
|
||||
|
||||
#endif
|
||||
|
||||
NSString* GCDWebServerNormalizeHeaderValue(NSString* value) {
|
||||
if (value) {
|
||||
NSRange range = [value rangeOfString:@";"]; // Assume part before ";" separator is case-insensitive
|
||||
if (range.location != NSNotFound) {
|
||||
value = [[[value substringToIndex:range.location] lowercaseString] stringByAppendingString:[value substringFromIndex:range.location]];
|
||||
} else {
|
||||
value = [value lowercaseString];
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerTruncateHeaderValue(NSString* value) {
|
||||
DCHECK([value isEqualToString:GCDWebServerNormalizeHeaderValue(value)]);
|
||||
NSRange range = [value rangeOfString:@";"];
|
||||
return range.location != NSNotFound ? [value substringToIndex:range.location] : value;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerExtractHeaderValueParameter(NSString* value, NSString* name) {
|
||||
DCHECK([value isEqualToString:GCDWebServerNormalizeHeaderValue(value)]);
|
||||
NSString* parameter = nil;
|
||||
NSScanner* scanner = [[NSScanner alloc] initWithString:value];
|
||||
[scanner setCaseSensitive:NO]; // Assume parameter names are case-insensitive
|
||||
NSString* string = [NSString stringWithFormat:@"%@=", name];
|
||||
if ([scanner scanUpToString:string intoString:NULL]) {
|
||||
[scanner scanString:string intoString:NULL];
|
||||
if ([scanner scanString:@"\"" intoString:NULL]) {
|
||||
[scanner scanUpToString:@"\"" intoString:¶meter];
|
||||
} else {
|
||||
[scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:¶meter];
|
||||
}
|
||||
}
|
||||
ARC_RELEASE(scanner);
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// http://www.w3schools.com/tags/ref_charactersets.asp
|
||||
NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
|
||||
NSStringEncoding encoding = kCFStringEncodingInvalidId;
|
||||
if (charset) {
|
||||
encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset));
|
||||
}
|
||||
return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
|
||||
}
|
||||
|
||||
NSString* GCDWebServerFormatHTTPDate(NSDate* date) {
|
||||
__block NSString* string;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
string = [_dateFormatterRFC822 stringFromDate:date]; // HTTP/1.1 server must use RFC822
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
NSDate* GCDWebServerParseHTTPDate(NSString* string) {
|
||||
__block NSDate* date;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
date = [_dateFormatterRFC822 dateFromString:string]; // TODO: Handle RFC 850 and ANSI C's asctime() format (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3)
|
||||
});
|
||||
return date;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType) {
|
||||
if ([contentType hasPrefix:@"text/"] || [contentType isEqualToString:@"application/json"] || [contentType isEqualToString:@"application/xml"]) {
|
||||
NSString* charset = GCDWebServerExtractHeaderValueParameter(contentType, @"charset");
|
||||
NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
|
||||
if (string) {
|
||||
return ARC_AUTORELEASE(string);
|
||||
}
|
||||
}
|
||||
return [NSString stringWithFormat:@"<%lu bytes>", (unsigned long)data.length];
|
||||
}
|
||||
|
||||
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
|
||||
static NSDictionary* _overrides = nil;
|
||||
if (_overrides == nil) {
|
||||
_overrides = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
@"text/css", @"css",
|
||||
nil];
|
||||
}
|
||||
NSString* mimeType = nil;
|
||||
extension = [extension lowercaseString];
|
||||
if (extension.length) {
|
||||
mimeType = [_overrides objectForKey:extension];
|
||||
if (mimeType == nil) {
|
||||
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (ARC_BRIDGE CFStringRef)extension, NULL);
|
||||
if (uti) {
|
||||
mimeType = ARC_BRIDGE_RELEASE(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
|
||||
CFRelease(uti);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mimeType ? mimeType : kGCDWebServerDefaultMimeType;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerEscapeURLString(NSString* string) {
|
||||
return ARC_BRIDGE_RELEASE(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
|
||||
}
|
||||
|
||||
NSString* GCDWebServerUnescapeURLString(NSString* string) {
|
||||
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) {
|
||||
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
|
||||
NSScanner* scanner = [[NSScanner alloc] initWithString:form];
|
||||
[scanner setCharactersToBeSkipped:nil];
|
||||
while (1) {
|
||||
NSString* key = nil;
|
||||
if (![scanner scanUpToString:@"=" intoString:&key] || [scanner isAtEnd]) {
|
||||
break;
|
||||
}
|
||||
[scanner setScanLocation:([scanner scanLocation] + 1)];
|
||||
|
||||
NSString* value = nil;
|
||||
if (![scanner scanUpToString:@"&" intoString:&value]) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "];
|
||||
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
|
||||
if (key && value) {
|
||||
[parameters setObject:GCDWebServerUnescapeURLString(value) forKey:GCDWebServerUnescapeURLString(key)];
|
||||
} else {
|
||||
DNOT_REACHED();
|
||||
}
|
||||
|
||||
if ([scanner isAtEnd]) {
|
||||
break;
|
||||
}
|
||||
[scanner setScanLocation:([scanner scanLocation] + 1)];
|
||||
}
|
||||
ARC_RELEASE(scanner);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerGetPrimaryIPv4Address() {
|
||||
NSString* address = nil;
|
||||
#if TARGET_OS_IPHONE
|
||||
#if !TARGET_IPHONE_SIMULATOR
|
||||
const char* primaryInterface = "en0"; // WiFi interface on iOS
|
||||
#endif
|
||||
#else
|
||||
const char* primaryInterface = NULL;
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("GCDWebServer"), NULL, NULL);
|
||||
if (store) {
|
||||
CFPropertyListRef info = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4"));
|
||||
if (info) {
|
||||
primaryInterface = [[(ARC_BRIDGE NSDictionary*)info objectForKey:@"PrimaryInterface"] UTF8String];
|
||||
CFRelease(info);
|
||||
}
|
||||
CFRelease(store);
|
||||
}
|
||||
if (primaryInterface == NULL) {
|
||||
primaryInterface = "lo0";
|
||||
}
|
||||
#endif
|
||||
struct ifaddrs* list;
|
||||
if (getifaddrs(&list) >= 0) {
|
||||
for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) {
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1")) // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
|
||||
#else
|
||||
if (strcmp(ifap->ifa_name, primaryInterface))
|
||||
#endif
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((ifap->ifa_flags & IFF_UP) && (ifap->ifa_addr->sa_family == AF_INET)) {
|
||||
char buffer[NI_MAXHOST];
|
||||
if (getnameinfo(ifap->ifa_addr, ifap->ifa_addr->sa_len, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST | NI_NOFQDN) >= 0) {
|
||||
address = [NSString stringWithUTF8String:buffer];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(list);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
|
||||
static void _SignalHandler(int signal) {
|
||||
@@ -318,18 +129,7 @@ static void _SignalHandler(int signal) {
|
||||
#endif
|
||||
|
||||
+ (void)initialize {
|
||||
if (_dateFormatterRFC822 == nil) {
|
||||
DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread
|
||||
_dateFormatterRFC822 = [[NSDateFormatter alloc] init];
|
||||
_dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
|
||||
_dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
|
||||
_dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
|
||||
DCHECK(_dateFormatterRFC822);
|
||||
}
|
||||
if (_dateFormatterQueue == NULL) {
|
||||
_dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
|
||||
DCHECK(_dateFormatterQueue);
|
||||
}
|
||||
GCDWebServerInitializeFunctions();
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
@@ -529,6 +329,18 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er
|
||||
|
||||
@implementation GCDWebServer (Extensions)
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
|
||||
- (void)setRecordingEnabled:(BOOL)flag {
|
||||
_recording = flag;
|
||||
}
|
||||
|
||||
- (BOOL)isRecordingEnabled {
|
||||
return _recording;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
- (NSURL*)serverURL {
|
||||
if (_source) {
|
||||
NSString* ipAddress = GCDWebServerGetPrimaryIPv4Address();
|
||||
@@ -578,6 +390,175 @@ static void _NetServiceClientCallBack(CFNetServiceRef service, CFStreamError* er
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||
|
||||
static CFHTTPMessageRef _CreateHTTPMessageFromData(NSData* data, BOOL isRequest) {
|
||||
CFHTTPMessageRef message = CFHTTPMessageCreateEmpty(kCFAllocatorDefault, isRequest);
|
||||
if (CFHTTPMessageAppendBytes(message, data.bytes, data.length)) {
|
||||
return message;
|
||||
}
|
||||
CFRelease(message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CFHTTPMessageRef _CreateHTTPMessageFromPerformingRequest(NSData* inData, NSUInteger port) {
|
||||
CFHTTPMessageRef response = NULL;
|
||||
int httpSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (httpSocket > 0) {
|
||||
struct sockaddr_in addr4;
|
||||
bzero(&addr4, sizeof(addr4));
|
||||
addr4.sin_len = sizeof(port);
|
||||
addr4.sin_family = AF_INET;
|
||||
addr4.sin_port = htons(8080);
|
||||
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
if (connect(httpSocket, (void*)&addr4, sizeof(addr4)) == 0) {
|
||||
if (write(httpSocket, inData.bytes, inData.length) == (ssize_t)inData.length) {
|
||||
NSMutableData* outData = [[NSMutableData alloc] initWithLength:(256 * 1024)];
|
||||
NSUInteger length = 0;
|
||||
while (1) {
|
||||
ssize_t result = read(httpSocket, (char*)outData.mutableBytes + length, outData.length - length);
|
||||
if (result < 0) {
|
||||
length = NSNotFound;
|
||||
break;
|
||||
} else if (result == 0) {
|
||||
break;
|
||||
}
|
||||
length += result;
|
||||
if (length >= outData.length) {
|
||||
outData.length = 2 * outData.length;
|
||||
}
|
||||
}
|
||||
if (length != NSNotFound) {
|
||||
outData.length = length;
|
||||
response = _CreateHTTPMessageFromData(outData, NO);
|
||||
} else {
|
||||
DNOT_REACHED();
|
||||
}
|
||||
ARC_RELEASE(outData);
|
||||
}
|
||||
}
|
||||
close(httpSocket);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
static void _LogResult(NSString* format, ...) {
|
||||
va_list arguments;
|
||||
va_start(arguments, format);
|
||||
NSString* message = [[NSString alloc] initWithFormat:format arguments:arguments];
|
||||
va_end(arguments);
|
||||
fprintf(stdout, "%s\n", [message UTF8String]);
|
||||
ARC_RELEASE(message);
|
||||
}
|
||||
|
||||
- (NSInteger)runTestsInDirectory:(NSString*)path withPort:(NSUInteger)port {
|
||||
NSArray* ignoredHeaders = @[@"Date", @"Etag"]; // Dates are always different by definition and ETags depend on file system node IDs
|
||||
NSInteger result = -1;
|
||||
if ([self startWithPort:port bonjourName:nil]) {
|
||||
|
||||
result = 0;
|
||||
NSArray* files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];
|
||||
for (NSString* requestFile in files) {
|
||||
if (![requestFile hasSuffix:@".request"]) {
|
||||
continue;
|
||||
}
|
||||
@autoreleasepool {
|
||||
NSString* index = [[requestFile componentsSeparatedByString:@"-"] firstObject];
|
||||
BOOL success = NO;
|
||||
NSData* requestData = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:requestFile]];
|
||||
if (requestData) {
|
||||
CFHTTPMessageRef request = _CreateHTTPMessageFromData(requestData, YES);
|
||||
if (request) {
|
||||
NSString* requestMethod = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(request));
|
||||
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(request));
|
||||
_LogResult(@"[%i] %@ %@", (int)[index integerValue], requestMethod, requestURL.path);
|
||||
NSString* prefix = [index stringByAppendingString:@"-"];
|
||||
for (NSString* responseFile in files) {
|
||||
if ([responseFile hasPrefix:prefix] && [responseFile hasSuffix:@".response"]) {
|
||||
NSData* responseData = [NSData dataWithContentsOfFile:[path stringByAppendingPathComponent:responseFile]];
|
||||
if (responseData) {
|
||||
CFHTTPMessageRef expectedResponse = _CreateHTTPMessageFromData(responseData, NO);
|
||||
if (expectedResponse) {
|
||||
CFHTTPMessageRef actualResponse = _CreateHTTPMessageFromPerformingRequest(requestData, port);
|
||||
if (actualResponse) {
|
||||
success = YES;
|
||||
|
||||
CFIndex expectedStatusCode = CFHTTPMessageGetResponseStatusCode(expectedResponse);
|
||||
CFIndex actualStatusCode = CFHTTPMessageGetResponseStatusCode(actualResponse);
|
||||
if (actualStatusCode != expectedStatusCode) {
|
||||
_LogResult(@" Status code not matching:\n Expected: %i\n Actual: %i", (int)expectedStatusCode, (int)actualStatusCode);
|
||||
success = NO;
|
||||
}
|
||||
|
||||
NSDictionary* expectedHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(expectedResponse));
|
||||
NSDictionary* actualHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(actualResponse));
|
||||
for (NSString* expectedHeader in expectedHeaders) {
|
||||
if ([ignoredHeaders containsObject:expectedHeader]) {
|
||||
continue;
|
||||
}
|
||||
NSString* expectedValue = [expectedHeaders objectForKey:expectedHeader];
|
||||
NSString* actualValue = [actualHeaders objectForKey:expectedHeader];
|
||||
if (![actualValue isEqualToString:expectedValue]) {
|
||||
_LogResult(@" Header '%@' not matching:\n Expected: \"%@\"\n Actual: \"%@\"", expectedHeader, expectedValue, actualValue);
|
||||
success = NO;
|
||||
}
|
||||
}
|
||||
for (NSString* actualHeader in actualHeaders) {
|
||||
if (![expectedHeaders objectForKey:actualHeader]) {
|
||||
_LogResult(@" Header '%@' not matching:\n Expected: \"%@\"\n Actual: \"%@\"", actualHeader, nil, [actualHeaders objectForKey:actualHeader]);
|
||||
success = NO;
|
||||
}
|
||||
}
|
||||
|
||||
NSData* expectedBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(expectedResponse));
|
||||
NSData* actualBody = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyBody(actualResponse));
|
||||
if (![actualBody isEqualToData:expectedBody]) {
|
||||
_LogResult(@" Bodies not matching:\n Expected: %lu bytes\n Actual: %lu bytes", (unsigned long)expectedBody.length, (unsigned long)actualBody.length);
|
||||
success = NO;
|
||||
#ifndef NDEBUG
|
||||
if (GCDWebServerIsTextContentType([expectedHeaders objectForKey:@"Content-Type"])) {
|
||||
NSString* expectedPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:@"txt"]];
|
||||
NSString* actualPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[[[NSProcessInfo processInfo] globallyUniqueString] stringByAppendingPathExtension:@"txt"]];
|
||||
if ([expectedBody writeToFile:expectedPath atomically:YES] && [actualBody writeToFile:actualPath atomically:YES]) {
|
||||
NSTask* task = [[NSTask alloc] init];
|
||||
[task setLaunchPath:@"/usr/bin/opendiff"];
|
||||
[task setArguments:@[expectedPath, actualPath]];
|
||||
[task launch];
|
||||
ARC_RELEASE(task);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CFRelease(actualResponse);
|
||||
}
|
||||
CFRelease(expectedResponse);
|
||||
}
|
||||
} else {
|
||||
DNOT_REACHED();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
CFRelease(request);
|
||||
}
|
||||
} else {
|
||||
DNOT_REACHED();
|
||||
}
|
||||
_LogResult(@"");
|
||||
if (!success) {
|
||||
++result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self stop];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation GCDWebServer (Handlers)
|
||||
@@ -25,7 +25,11 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#import <netdb.h>
|
||||
#if !TARGET_OS_IPHONE
|
||||
#import <libkern/OSAtomic.h>
|
||||
#endif
|
||||
|
||||
#import "GCDWebServerPrivate.h"
|
||||
|
||||
@@ -45,6 +49,9 @@ static NSData* _CRLFData = nil;
|
||||
static NSData* _CRLFCRLFData = nil;
|
||||
static NSData* _continueData = nil;
|
||||
static NSData* _lastChunkData = nil;
|
||||
#if !TARGET_OS_IPHONE
|
||||
static int32_t _connectionCounter = 0;
|
||||
#endif
|
||||
|
||||
@interface GCDWebServerConnection () {
|
||||
@private
|
||||
@@ -62,6 +69,14 @@ static NSData* _lastChunkData = nil;
|
||||
CFHTTPMessageRef _responseMessage;
|
||||
GCDWebServerResponse* _response;
|
||||
NSInteger _statusCode;
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
NSUInteger _connectionIndex;
|
||||
NSString* _requestPath;
|
||||
int _requestFD;
|
||||
NSString* _responsePath;
|
||||
int _responseFD;
|
||||
#endif
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -77,6 +92,18 @@ static NSData* _lastChunkData = nil;
|
||||
LOG_DEBUG(@"Connection received %zu bytes on socket %i", size, _socket);
|
||||
_bytesRead += size;
|
||||
[self didUpdateBytesRead];
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (_requestFD > 0) {
|
||||
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
return (write(_requestFD, chunkBytes, chunkSize) == (ssize_t)chunkSize);
|
||||
});
|
||||
if (!success) {
|
||||
LOG_ERROR(@"Failed recording request data: %s (%i)", strerror(errno), errno);
|
||||
close(_requestFD);
|
||||
_requestFD = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
block(buffer);
|
||||
} else {
|
||||
if (_bytesRead > 0) {
|
||||
@@ -100,8 +127,8 @@ static NSData* _lastChunkData = nil;
|
||||
|
||||
if (buffer) {
|
||||
NSMutableData* data = [[NSMutableData alloc] initWithCapacity:dispatch_data_get_size(buffer)];
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* bufferChunk, size_t size) {
|
||||
[data appendBytes:bufferChunk length:size];
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
[data appendBytes:chunkBytes length:chunkSize];
|
||||
return true;
|
||||
});
|
||||
block(data);
|
||||
@@ -119,8 +146,8 @@ static NSData* _lastChunkData = nil;
|
||||
|
||||
if (buffer) {
|
||||
NSMutableData* data = [NSMutableData dataWithCapacity:kHeadersReadBuffer];
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* bufferChunk, size_t size) {
|
||||
[data appendBytes:bufferChunk length:size];
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
[data appendBytes:chunkBytes length:chunkSize];
|
||||
return true;
|
||||
});
|
||||
NSRange range = [data rangeOfData:_CRLFCRLFData options:0 range:NSMakeRange(0, data.length)];
|
||||
@@ -158,7 +185,7 @@ static NSData* _lastChunkData = nil;
|
||||
|
||||
if (buffer) {
|
||||
if (dispatch_data_get_size(buffer) <= length) {
|
||||
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* chunkBytes, size_t chunkSize) {
|
||||
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
NSData* data = [NSData dataWithBytesNoCopy:(void*)chunkBytes length:chunkSize freeWhenDone:NO];
|
||||
NSError* error = nil;
|
||||
if (![_request performWriteData:data error:&error]) {
|
||||
@@ -245,7 +272,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
[self _readBufferWithLength:SIZE_T_MAX completionBlock:^(dispatch_data_t buffer) {
|
||||
|
||||
if (buffer) {
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t offset, const void* chunkBytes, size_t chunkSize) {
|
||||
dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
[chunkData appendBytes:chunkBytes length:chunkSize];
|
||||
return true;
|
||||
});
|
||||
@@ -263,6 +290,9 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
|
||||
- (void)_writeBuffer:(dispatch_data_t)buffer withCompletionBlock:(WriteBufferCompletionBlock)block {
|
||||
size_t size = dispatch_data_get_size(buffer);
|
||||
#if !TARGET_OS_IPHONE
|
||||
ARC_DISPATCH_RETAIN(buffer);
|
||||
#endif
|
||||
dispatch_write(_socket, buffer, kGCDWebServerGCDQueue, ^(dispatch_data_t data, int error) {
|
||||
|
||||
@autoreleasepool {
|
||||
@@ -271,12 +301,27 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
LOG_DEBUG(@"Connection sent %zu bytes on socket %i", size, _socket);
|
||||
_bytesWritten += size;
|
||||
[self didUpdateBytesWritten];
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (_responseFD > 0) {
|
||||
bool success = dispatch_data_apply(buffer, ^bool(dispatch_data_t region, size_t chunkOffset, const void* chunkBytes, size_t chunkSize) {
|
||||
return (write(_responseFD, chunkBytes, chunkSize) == (ssize_t)chunkSize);
|
||||
});
|
||||
if (!success) {
|
||||
LOG_ERROR(@"Failed recording response data: %s (%i)", strerror(errno), errno);
|
||||
close(_responseFD);
|
||||
_responseFD = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
block(YES);
|
||||
} else {
|
||||
LOG_ERROR(@"Error while writing to socket %i: %s (%i)", _socket, strerror(error), error);
|
||||
block(NO);
|
||||
}
|
||||
}
|
||||
#if !TARGET_OS_IPHONE
|
||||
ARC_DISPATCH_RELEASE(buffer);
|
||||
#endif
|
||||
|
||||
});
|
||||
}
|
||||
@@ -285,7 +330,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
#if !__has_feature(objc_arc)
|
||||
[data retain];
|
||||
#endif
|
||||
dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, dispatch_get_main_queue(), ^{
|
||||
dispatch_data_t buffer = dispatch_data_create(data.bytes, data.length, kGCDWebServerGCDQueue, ^{
|
||||
#if __has_feature(objc_arc)
|
||||
[data self]; // Keeps ARC from releasing data too early
|
||||
#else
|
||||
@@ -390,7 +435,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
_responseMessage = CFHTTPMessageCreateResponse(kCFAllocatorDefault, statusCode, NULL, kCFHTTPVersion1_1);
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Connection"), CFSTR("Close"));
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Server"), (ARC_BRIDGE CFStringRef)[[_server class] serverName]);
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate([NSDate date]));
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Date"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822([NSDate date]));
|
||||
}
|
||||
|
||||
// http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
|
||||
@@ -418,7 +463,7 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
if (_response) {
|
||||
[self _initializeResponseHeadersWithStatusCode:_response.statusCode];
|
||||
if (_response.lastModifiedDate) {
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatHTTPDate(_response.lastModifiedDate));
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("Last-Modified"), (ARC_BRIDGE CFStringRef)GCDWebServerFormatRFC822(_response.lastModifiedDate));
|
||||
}
|
||||
if (_response.eTag) {
|
||||
CFHTTPMessageSetHeaderFieldValue(_responseMessage, CFSTR("ETag"), (ARC_BRIDGE CFStringRef)_response.eTag);
|
||||
@@ -534,69 +579,66 @@ static inline NSUInteger _ScanHexNumber(const void* bytes, NSUInteger size) {
|
||||
|
||||
if (extraData) {
|
||||
NSString* requestMethod = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestMethod(_requestMessage)); // Method verbs are case-sensitive and uppercase
|
||||
DCHECK(requestMethod);
|
||||
if ([[_server class] shouldAutomaticallyMapHEADToGET] && [requestMethod isEqualToString:@"HEAD"]) {
|
||||
requestMethod = @"GET";
|
||||
_virtualHEAD = YES;
|
||||
}
|
||||
NSURL* requestURL = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyRequestURL(_requestMessage));
|
||||
DCHECK(requestURL);
|
||||
NSString* requestPath = GCDWebServerUnescapeURLString(ARC_BRIDGE_RELEASE(CFURLCopyPath((CFURLRef)requestURL))); // Don't use -[NSURL path] which strips the ending slash
|
||||
DCHECK(requestPath);
|
||||
NSDictionary* requestQuery = nil;
|
||||
NSString* queryString = ARC_BRIDGE_RELEASE(CFURLCopyQueryString((CFURLRef)requestURL, NULL)); // Don't use -[NSURL query] to make sure query is not unescaped;
|
||||
if (queryString.length) {
|
||||
requestQuery = GCDWebServerParseURLEncodedForm(queryString);
|
||||
DCHECK(requestQuery);
|
||||
}
|
||||
NSString* requestPath = requestURL ? GCDWebServerUnescapeURLString(ARC_BRIDGE_RELEASE(CFURLCopyPath((CFURLRef)requestURL))) : nil; // Don't use -[NSURL path] which strips the ending slash
|
||||
NSString* queryString = requestURL ? ARC_BRIDGE_RELEASE(CFURLCopyQueryString((CFURLRef)requestURL, NULL)) : nil; // Don't use -[NSURL query] to make sure query is not unescaped;
|
||||
NSDictionary* requestQuery = queryString ? GCDWebServerParseURLEncodedForm(queryString) : @{};
|
||||
NSDictionary* requestHeaders = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyAllHeaderFields(_requestMessage)); // Header names are case-insensitive but CFHTTPMessageCopyAllHeaderFields() will standardize the common ones
|
||||
DCHECK(requestHeaders);
|
||||
for (_handler in _server.handlers) {
|
||||
_request = ARC_RETAIN(_handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery));
|
||||
if (_request) {
|
||||
break;
|
||||
if (requestMethod && requestURL && requestHeaders && requestPath && requestQuery) {
|
||||
for (_handler in _server.handlers) {
|
||||
_request = ARC_RETAIN(_handler.matchBlock(requestMethod, requestURL, requestHeaders, requestPath, requestQuery));
|
||||
if (_request) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_request) {
|
||||
if ([_request hasBody]) {
|
||||
[_request prepareForWriting];
|
||||
if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
|
||||
NSString* expectHeader = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")));
|
||||
if (expectHeader) {
|
||||
if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) {
|
||||
[self _writeData:_continueData withCompletionBlock:^(BOOL success) {
|
||||
|
||||
if (success) {
|
||||
if (_request.usesChunkedTransferEncoding) {
|
||||
[self _readChunkedBodyWithInitialData:extraData];
|
||||
} else {
|
||||
[self _readBodyWithLength:_request.contentLength initialData:extraData];
|
||||
if (_request) {
|
||||
if ([_request hasBody]) {
|
||||
[_request prepareForWriting];
|
||||
if (_request.usesChunkedTransferEncoding || (extraData.length <= _request.contentLength)) {
|
||||
NSString* expectHeader = ARC_BRIDGE_RELEASE(CFHTTPMessageCopyHeaderFieldValue(_requestMessage, CFSTR("Expect")));
|
||||
if (expectHeader) {
|
||||
if ([expectHeader caseInsensitiveCompare:@"100-continue"] == NSOrderedSame) {
|
||||
[self _writeData:_continueData withCompletionBlock:^(BOOL success) {
|
||||
|
||||
if (success) {
|
||||
if (_request.usesChunkedTransferEncoding) {
|
||||
[self _readChunkedBodyWithInitialData:extraData];
|
||||
} else {
|
||||
[self _readBodyWithLength:_request.contentLength initialData:extraData];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}];
|
||||
|
||||
}];
|
||||
} else {
|
||||
LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed];
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(@"Unsupported 'Expect' / 'Content-Length' header combination on socket %i", _socket);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_ExpectationFailed];
|
||||
if (_request.usesChunkedTransferEncoding) {
|
||||
[self _readChunkedBodyWithInitialData:extraData];
|
||||
} else {
|
||||
[self _readBodyWithLength:_request.contentLength initialData:extraData];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_request.usesChunkedTransferEncoding) {
|
||||
[self _readChunkedBodyWithInitialData:extraData];
|
||||
} else {
|
||||
[self _readBodyWithLength:_request.contentLength initialData:extraData];
|
||||
}
|
||||
LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest];
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(@"Unexpected 'Content-Length' header value on socket %i", _socket);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_BadRequest];
|
||||
[self _processRequest];
|
||||
}
|
||||
} else {
|
||||
[self _processRequest];
|
||||
_request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery];
|
||||
DCHECK(_request);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed];
|
||||
}
|
||||
} else {
|
||||
_request = [[GCDWebServerRequest alloc] initWithMethod:requestMethod url:requestURL headers:requestHeaders path:requestPath query:requestQuery];
|
||||
DCHECK(_request);
|
||||
[self abortRequest:_request withStatusCode:kGCDWebServerHTTPStatusCode_MethodNotAllowed];
|
||||
[self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
|
||||
DNOT_REACHED();
|
||||
}
|
||||
} else {
|
||||
[self abortRequest:nil withStatusCode:kGCDWebServerHTTPStatusCode_InternalServerError];
|
||||
@@ -655,6 +697,11 @@ static NSString* _StringFromAddressData(NSData* data) {
|
||||
}
|
||||
ARC_RELEASE(_response);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
ARC_RELEASE(_requestPath);
|
||||
ARC_RELEASE(_responsePath);
|
||||
#endif
|
||||
|
||||
ARC_DEALLOC(super);
|
||||
}
|
||||
|
||||
@@ -664,6 +711,21 @@ static NSString* _StringFromAddressData(NSData* data) {
|
||||
|
||||
- (void)open {
|
||||
LOG_DEBUG(@"Did open connection on socket %i", _socket);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (_server.recordingEnabled) {
|
||||
_connectionIndex = OSAtomicIncrement32(&_connectionCounter);
|
||||
|
||||
_requestPath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
|
||||
_requestFD = open([_requestPath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY);
|
||||
DCHECK(_requestFD > 0);
|
||||
|
||||
_responsePath = ARC_RETAIN([NSTemporaryDirectory() stringByAppendingPathComponent:[[NSProcessInfo processInfo] globallyUniqueString]]);
|
||||
_responseFD = open([_responsePath fileSystemRepresentation], O_CREAT | O_TRUNC | O_WRONLY);
|
||||
DCHECK(_responseFD > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
[self _readRequestHeaders];
|
||||
}
|
||||
|
||||
@@ -732,7 +794,43 @@ static inline BOOL _CompareResources(NSString* responseETag, NSString* requestET
|
||||
} else {
|
||||
LOG_DEBUG(@"Did close connection on socket %i", _socket);
|
||||
}
|
||||
LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
if (_requestPath) {
|
||||
BOOL success = NO;
|
||||
NSError* error = nil;
|
||||
if (_requestFD > 0) {
|
||||
close(_requestFD);
|
||||
NSString* name = [NSString stringWithFormat:@"%03lu-%@.request", (unsigned long)_connectionIndex, _virtualHEAD ? @"HEAD" : _request.method];
|
||||
success = [[NSFileManager defaultManager] moveItemAtPath:_requestPath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
|
||||
}
|
||||
if (!success) {
|
||||
LOG_ERROR(@"Failed saving recorded request: %@", error);
|
||||
DNOT_REACHED();
|
||||
}
|
||||
unlink([_requestPath fileSystemRepresentation]);
|
||||
}
|
||||
|
||||
if (_responsePath) {
|
||||
BOOL success = NO;
|
||||
NSError* error = nil;
|
||||
if (_responseFD > 0) {
|
||||
close(_responseFD);
|
||||
NSString* name = [NSString stringWithFormat:@"%03lu-%i.response", (unsigned long)_connectionIndex, (int)_statusCode];
|
||||
success = [[NSFileManager defaultManager] moveItemAtPath:_responsePath toPath:[[[NSFileManager defaultManager] currentDirectoryPath] stringByAppendingPathComponent:name] error:&error];
|
||||
}
|
||||
if (!success) {
|
||||
LOG_ERROR(@"Failed saving recorded response: %@", error);
|
||||
DNOT_REACHED();
|
||||
}
|
||||
unlink([_responsePath fileSystemRepresentation]);
|
||||
}
|
||||
#endif
|
||||
if (_request) {
|
||||
LOG_VERBOSE(@"[%@] %@ %i \"%@ %@\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, _virtualHEAD ? @"HEAD" : _request.method, _request.path, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
||||
} else {
|
||||
LOG_VERBOSE(@"[%@] %@ %i \"(invalid request)\" (%lu | %lu)", self.localAddressString, self.remoteAddressString, (int)_statusCode, (unsigned long)_bytesRead, (unsigned long)_bytesWritten);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
46
GCDWebServer/Core/GCDWebServerFunctions.h
Normal file
46
GCDWebServer/Core/GCDWebServerFunctions.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014, Pierre-Olivier Latour
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The name of Pierre-Olivier Latour may not be used to endorse
|
||||
or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension);
|
||||
NSString* GCDWebServerEscapeURLString(NSString* string);
|
||||
NSString* GCDWebServerUnescapeURLString(NSString* string);
|
||||
NSDictionary* GCDWebServerParseURLEncodedForm(NSString* form);
|
||||
NSString* GCDWebServerGetPrimaryIPv4Address(); // Returns IPv4 address of primary connected service on OS X or of WiFi interface on iOS if connected
|
||||
NSString* GCDWebServerFormatRFC822(NSDate* date);
|
||||
NSDate* GCDWebServerParseRFC822(NSString* string);
|
||||
NSString* GCDWebServerFormatISO8601(NSDate* date);
|
||||
NSDate* GCDWebServerParseISO8601(NSString* string);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
268
GCDWebServer/Core/GCDWebServerFunctions.m
Normal file
268
GCDWebServer/Core/GCDWebServerFunctions.m
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
Copyright (c) 2012-2014, Pierre-Olivier Latour
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* The name of Pierre-Olivier Latour may not be used to endorse
|
||||
or promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL PIERRE-OLIVIER LATOUR BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#if TARGET_OS_IPHONE
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#else
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#endif
|
||||
|
||||
#import <ifaddrs.h>
|
||||
#import <net/if.h>
|
||||
#import <netdb.h>
|
||||
|
||||
#import "GCDWebServerPrivate.h"
|
||||
|
||||
static NSDateFormatter* _dateFormatterRFC822 = nil;
|
||||
static NSDateFormatter* _dateFormatterISO8601 = nil;
|
||||
static dispatch_queue_t _dateFormatterQueue = NULL;
|
||||
|
||||
// HTTP/1.1 server must use RFC822
|
||||
// TODO: Handle RFC 850 and ANSI C's asctime() format (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3)
|
||||
void GCDWebServerInitializeFunctions() {
|
||||
DCHECK([NSThread isMainThread]); // NSDateFormatter should be initialized on main thread
|
||||
if (_dateFormatterRFC822 == nil) {
|
||||
_dateFormatterRFC822 = [[NSDateFormatter alloc] init];
|
||||
_dateFormatterRFC822.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
|
||||
_dateFormatterRFC822.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'";
|
||||
_dateFormatterRFC822.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
|
||||
DCHECK(_dateFormatterRFC822);
|
||||
}
|
||||
if (_dateFormatterISO8601 == nil) {
|
||||
_dateFormatterISO8601 = [[NSDateFormatter alloc] init];
|
||||
_dateFormatterISO8601.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
|
||||
_dateFormatterISO8601.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss'+00:00'";
|
||||
_dateFormatterISO8601.locale = ARC_AUTORELEASE([[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]);
|
||||
DCHECK(_dateFormatterISO8601);
|
||||
}
|
||||
if (_dateFormatterQueue == NULL) {
|
||||
_dateFormatterQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
|
||||
DCHECK(_dateFormatterQueue);
|
||||
}
|
||||
}
|
||||
|
||||
NSString* GCDWebServerNormalizeHeaderValue(NSString* value) {
|
||||
if (value) {
|
||||
NSRange range = [value rangeOfString:@";"]; // Assume part before ";" separator is case-insensitive
|
||||
if (range.location != NSNotFound) {
|
||||
value = [[[value substringToIndex:range.location] lowercaseString] stringByAppendingString:[value substringFromIndex:range.location]];
|
||||
} else {
|
||||
value = [value lowercaseString];
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerTruncateHeaderValue(NSString* value) {
|
||||
DCHECK([value isEqualToString:GCDWebServerNormalizeHeaderValue(value)]);
|
||||
NSRange range = [value rangeOfString:@";"];
|
||||
return range.location != NSNotFound ? [value substringToIndex:range.location] : value;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerExtractHeaderValueParameter(NSString* value, NSString* name) {
|
||||
DCHECK([value isEqualToString:GCDWebServerNormalizeHeaderValue(value)]);
|
||||
NSString* parameter = nil;
|
||||
NSScanner* scanner = [[NSScanner alloc] initWithString:value];
|
||||
[scanner setCaseSensitive:NO]; // Assume parameter names are case-insensitive
|
||||
NSString* string = [NSString stringWithFormat:@"%@=", name];
|
||||
if ([scanner scanUpToString:string intoString:NULL]) {
|
||||
[scanner scanString:string intoString:NULL];
|
||||
if ([scanner scanString:@"\"" intoString:NULL]) {
|
||||
[scanner scanUpToString:@"\"" intoString:¶meter];
|
||||
} else {
|
||||
[scanner scanUpToCharactersFromSet:[NSCharacterSet whitespaceCharacterSet] intoString:¶meter];
|
||||
}
|
||||
}
|
||||
ARC_RELEASE(scanner);
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// http://www.w3schools.com/tags/ref_charactersets.asp
|
||||
NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset) {
|
||||
NSStringEncoding encoding = kCFStringEncodingInvalidId;
|
||||
if (charset) {
|
||||
encoding = CFStringConvertEncodingToNSStringEncoding(CFStringConvertIANACharSetNameToEncoding((CFStringRef)charset));
|
||||
}
|
||||
return (encoding != kCFStringEncodingInvalidId ? encoding : NSUTF8StringEncoding);
|
||||
}
|
||||
|
||||
NSString* GCDWebServerFormatRFC822(NSDate* date) {
|
||||
__block NSString* string;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
string = [_dateFormatterRFC822 stringFromDate:date];
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
NSDate* GCDWebServerParseRFC822(NSString* string) {
|
||||
__block NSDate* date;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
date = [_dateFormatterRFC822 dateFromString:string];
|
||||
});
|
||||
return date;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerFormatISO8601(NSDate* date) {
|
||||
__block NSString* string;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
string = [_dateFormatterISO8601 stringFromDate:date];
|
||||
});
|
||||
return string;
|
||||
}
|
||||
|
||||
NSDate* GCDWebServerParseISO8601(NSString* string) {
|
||||
__block NSDate* date;
|
||||
dispatch_sync(_dateFormatterQueue, ^{
|
||||
date = [_dateFormatterISO8601 dateFromString:string];
|
||||
});
|
||||
return date;
|
||||
}
|
||||
|
||||
BOOL GCDWebServerIsTextContentType(NSString* type) {
|
||||
return ([type hasPrefix:@"text/"] || [type hasPrefix:@"application/json"] || [type hasPrefix:@"application/xml"]);
|
||||
}
|
||||
|
||||
NSString* GCDWebServerDescribeData(NSData* data, NSString* type) {
|
||||
if (GCDWebServerIsTextContentType(type)) {
|
||||
NSString* charset = GCDWebServerExtractHeaderValueParameter(type, @"charset");
|
||||
NSString* string = [[NSString alloc] initWithData:data encoding:GCDWebServerStringEncodingFromCharset(charset)];
|
||||
if (string) {
|
||||
return ARC_AUTORELEASE(string);
|
||||
}
|
||||
}
|
||||
return [NSString stringWithFormat:@"<%lu bytes>", (unsigned long)data.length];
|
||||
}
|
||||
|
||||
NSString* GCDWebServerGetMimeTypeForExtension(NSString* extension) {
|
||||
static NSDictionary* _overrides = nil;
|
||||
if (_overrides == nil) {
|
||||
_overrides = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
@"text/css", @"css",
|
||||
nil];
|
||||
}
|
||||
NSString* mimeType = nil;
|
||||
extension = [extension lowercaseString];
|
||||
if (extension.length) {
|
||||
mimeType = [_overrides objectForKey:extension];
|
||||
if (mimeType == nil) {
|
||||
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (ARC_BRIDGE CFStringRef)extension, NULL);
|
||||
if (uti) {
|
||||
mimeType = ARC_BRIDGE_RELEASE(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType));
|
||||
CFRelease(uti);
|
||||
}
|
||||
}
|
||||
}
|
||||
return mimeType ? mimeType : kGCDWebServerDefaultMimeType;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerEscapeURLString(NSString* string) {
|
||||
return ARC_BRIDGE_RELEASE(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":@/?&=+"), kCFStringEncodingUTF8));
|
||||
}
|
||||
|
||||
NSString* GCDWebServerUnescapeURLString(NSString* string) {
|
||||
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) {
|
||||
NSMutableDictionary* parameters = [NSMutableDictionary dictionary];
|
||||
NSScanner* scanner = [[NSScanner alloc] initWithString:form];
|
||||
[scanner setCharactersToBeSkipped:nil];
|
||||
while (1) {
|
||||
NSString* key = nil;
|
||||
if (![scanner scanUpToString:@"=" intoString:&key] || [scanner isAtEnd]) {
|
||||
break;
|
||||
}
|
||||
[scanner setScanLocation:([scanner scanLocation] + 1)];
|
||||
|
||||
NSString* value = nil;
|
||||
if (![scanner scanUpToString:@"&" intoString:&value]) {
|
||||
break;
|
||||
}
|
||||
|
||||
key = [key stringByReplacingOccurrencesOfString:@"+" withString:@" "];
|
||||
value = [value stringByReplacingOccurrencesOfString:@"+" withString:@" "];
|
||||
if (key && value) {
|
||||
[parameters setObject:GCDWebServerUnescapeURLString(value) forKey:GCDWebServerUnescapeURLString(key)];
|
||||
} else {
|
||||
DNOT_REACHED();
|
||||
}
|
||||
|
||||
if ([scanner isAtEnd]) {
|
||||
break;
|
||||
}
|
||||
[scanner setScanLocation:([scanner scanLocation] + 1)];
|
||||
}
|
||||
ARC_RELEASE(scanner);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
NSString* GCDWebServerGetPrimaryIPv4Address() {
|
||||
NSString* address = nil;
|
||||
#if TARGET_OS_IPHONE
|
||||
#if !TARGET_IPHONE_SIMULATOR
|
||||
const char* primaryInterface = "en0"; // WiFi interface on iOS
|
||||
#endif
|
||||
#else
|
||||
const char* primaryInterface = NULL;
|
||||
SCDynamicStoreRef store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("GCDWebServer"), NULL, NULL);
|
||||
if (store) {
|
||||
CFPropertyListRef info = SCDynamicStoreCopyValue(store, CFSTR("State:/Network/Global/IPv4"));
|
||||
if (info) {
|
||||
primaryInterface = [[NSString stringWithString:[(ARC_BRIDGE NSDictionary*)info objectForKey:@"PrimaryInterface"]] UTF8String];
|
||||
CFRelease(info);
|
||||
}
|
||||
CFRelease(store);
|
||||
}
|
||||
if (primaryInterface == NULL) {
|
||||
primaryInterface = "lo0";
|
||||
}
|
||||
#endif
|
||||
struct ifaddrs* list;
|
||||
if (getifaddrs(&list) >= 0) {
|
||||
for (struct ifaddrs* ifap = list; ifap; ifap = ifap->ifa_next) {
|
||||
#if TARGET_IPHONE_SIMULATOR
|
||||
if (strcmp(ifap->ifa_name, "en0") && strcmp(ifap->ifa_name, "en1")) // Assume en0 is Ethernet and en1 is WiFi since there is no way to use SystemConfiguration framework in iOS Simulator
|
||||
#else
|
||||
if (strcmp(ifap->ifa_name, primaryInterface))
|
||||
#endif
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((ifap->ifa_flags & IFF_UP) && (ifap->ifa_addr->sa_family == AF_INET)) {
|
||||
char buffer[NI_MAXHOST];
|
||||
if (getnameinfo(ifap->ifa_addr, ifap->ifa_addr->sa_len, buffer, sizeof(buffer), NULL, 0, NI_NUMERICHOST | NI_NOFQDN) >= 0) {
|
||||
address = [NSString stringWithUTF8String:buffer];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
freeifaddrs(list);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
@@ -36,8 +36,10 @@
|
||||
#define ARC_AUTORELEASE(__OBJECT__) __OBJECT__
|
||||
#define ARC_DEALLOC(__OBJECT__)
|
||||
#if (TARGET_OS_IPHONE && (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_6_0)) || (!TARGET_OS_IPHONE && (__MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8))
|
||||
#define ARC_DISPATCH_RETAIN(__OBJECT__)
|
||||
#define ARC_DISPATCH_RELEASE(__OBJECT__)
|
||||
#else
|
||||
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
|
||||
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
||||
#endif
|
||||
#else
|
||||
@@ -47,11 +49,14 @@
|
||||
#define ARC_RELEASE(__OBJECT__) [__OBJECT__ release]
|
||||
#define ARC_AUTORELEASE(__OBJECT__) [__OBJECT__ autorelease]
|
||||
#define ARC_DEALLOC(__OBJECT__) [__OBJECT__ dealloc]
|
||||
#define ARC_DISPATCH_RETAIN(__OBJECT__) dispatch_retain(__OBJECT__)
|
||||
#define ARC_DISPATCH_RELEASE(__OBJECT__) dispatch_release(__OBJECT__)
|
||||
#endif
|
||||
|
||||
#import "GCDWebServerHTTPStatusCodes.h"
|
||||
#import "GCDWebServerFunctions.h"
|
||||
|
||||
#import "GCDWebServer.h"
|
||||
#import "GCDWebServerConnection.h"
|
||||
|
||||
#import "GCDWebServerDataRequest.h"
|
||||
@@ -109,12 +114,12 @@ static inline BOOL GCDWebServerIsValidByteRange(NSRange range) {
|
||||
return ((range.location != NSNotFound) || (range.length > 0));
|
||||
}
|
||||
|
||||
extern void GCDWebServerInitializeFunctions();
|
||||
extern NSString* GCDWebServerNormalizeHeaderValue(NSString* value);
|
||||
extern NSString* GCDWebServerTruncateHeaderValue(NSString* value);
|
||||
extern NSString* GCDWebServerExtractHeaderValueParameter(NSString* header, NSString* attribute);
|
||||
extern NSStringEncoding GCDWebServerStringEncodingFromCharset(NSString* charset);
|
||||
extern NSString* GCDWebServerFormatHTTPDate(NSDate* date);
|
||||
extern NSDate* GCDWebServerParseHTTPDate(NSString* string);
|
||||
extern BOOL GCDWebServerIsTextContentType(NSString* type);
|
||||
extern NSString* GCDWebServerDescribeData(NSData* data, NSString* contentType);
|
||||
|
||||
@interface GCDWebServerConnection ()
|
||||
@@ -44,7 +44,7 @@
|
||||
@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)
|
||||
@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, -bytes] from end)
|
||||
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding;
|
||||
@property(nonatomic, readonly) BOOL acceptsGzipContentEncoding; // Automatically parsed from headers
|
||||
- (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"
|
||||
@@ -199,7 +199,7 @@
|
||||
|
||||
NSString* modifiedHeader = [_headers objectForKey:@"If-Modified-Since"];
|
||||
if (modifiedHeader) {
|
||||
_modifiedSince = [GCDWebServerParseHTTPDate(modifiedHeader) copy];
|
||||
_modifiedSince = [GCDWebServerParseRFC822(modifiedHeader) copy];
|
||||
}
|
||||
_noneMatch = ARC_RETAIN([_headers objectForKey:@"If-None-Match"]);
|
||||
|
||||
@@ -78,6 +78,22 @@ static inline NSError* _MakePosixError(int code) {
|
||||
*error = _MakePosixError(errno);
|
||||
return NO;
|
||||
}
|
||||
#ifdef __GCDWEBSERVER_ENABLE_TESTING__
|
||||
NSString* creationDateHeader = [self.headers objectForKey:@"X-GCDWebServer-CreationDate"];
|
||||
if (creationDateHeader) {
|
||||
NSDate* date = GCDWebServerParseISO8601(creationDateHeader);
|
||||
if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileCreationDate: date} ofItemAtPath:_temporaryPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
NSString* modifiedDateHeader = [self.headers objectForKey:@"X-GCDWebServer-ModifiedDate"];
|
||||
if (modifiedDateHeader) {
|
||||
NSDate* date = GCDWebServerParseRFC822(modifiedDateHeader);
|
||||
if (!date || ![[NSFileManager defaultManager] setAttributes:@{NSFileModificationDate: date} ofItemAtPath:_temporaryPath error:error]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return YES;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
</div>
|
||||
|
||||
<script type="text/x-tmpl" id="template-listing">
|
||||
<tr class="row-file" data-path="{%=o.path%}" data-name="{%=o.name%}">
|
||||
<tr class="row-file">
|
||||
<td class="column-icon">
|
||||
{% if (o.size != null) { %}
|
||||
<button type="button" class="btn btn-default btn-xs button-download">
|
||||
|
||||
@@ -25,9 +25,11 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
var ENTER_KEYCODE = 13;
|
||||
|
||||
var _path = null;
|
||||
var _reloading = false;
|
||||
var _pendingReloads = [];
|
||||
var _reloadingDisabled = 0;
|
||||
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes >= 1000000000) {
|
||||
@@ -47,15 +49,27 @@ function _showError(message, textStatus, errorThrown) {
|
||||
}));
|
||||
}
|
||||
|
||||
function _disableReloads() {
|
||||
_reloadingDisabled += 1;
|
||||
}
|
||||
|
||||
function _enableReloads() {
|
||||
_reloadingDisabled -= 1;
|
||||
|
||||
if (_pendingReloads.length > 0) {
|
||||
_reload(_pendingReloads.shift());
|
||||
}
|
||||
}
|
||||
|
||||
function _reload(path) {
|
||||
if (_reloading) {
|
||||
if (_reloadingDisabled) {
|
||||
if ($.inArray(path, _pendingReloads) < 0) {
|
||||
_pendingReloads.push(path);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_reloading = true;
|
||||
_disableReloads();
|
||||
$.ajax({
|
||||
url: 'list',
|
||||
type: 'GET',
|
||||
@@ -64,6 +78,7 @@ function _reload(path) {
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
_showError("Failed retrieving contents of \"" + path + "\"", textStatus, errorThrown);
|
||||
}).done(function(data, textStatus, jqXHR) {
|
||||
var scrollPosition = $(document).scrollTop();
|
||||
|
||||
if (path != _path) {
|
||||
$("#path").empty();
|
||||
@@ -77,7 +92,7 @@ function _reload(path) {
|
||||
$("#path").append('<li data-path="' + subpath + '"><a>' + components[i] + '</a></li>');
|
||||
}
|
||||
$("#path > li").click(function(event) {
|
||||
_reload($(this).attr("data-path"));
|
||||
_reload($(this).data("path"));
|
||||
event.preventDefault();
|
||||
});
|
||||
$("#path").append('<li class="active">' + components[components.length - 1] + '</li>');
|
||||
@@ -87,13 +102,13 @@ function _reload(path) {
|
||||
|
||||
$("#listing").empty();
|
||||
for (var i = 0, file; file = data[i]; ++i) {
|
||||
$("#listing").append(tmpl("template-listing", file));
|
||||
$(tmpl("template-listing", file)).data(file).appendTo("#listing");
|
||||
}
|
||||
|
||||
$(".edit").editable(function(value, settings) {
|
||||
var name = $(this).parent().parent().attr("data-name");
|
||||
var name = $(this).parent().parent().data("name");
|
||||
if (value != name) {
|
||||
var path = $(this).parent().parent().attr("data-path");
|
||||
var path = $(this).parent().parent().data("path");
|
||||
$.ajax({
|
||||
url: 'move',
|
||||
type: 'POST',
|
||||
@@ -107,33 +122,42 @@ function _reload(path) {
|
||||
}
|
||||
return value;
|
||||
}, {
|
||||
onedit: function(settings, original) {
|
||||
_disableReloads();
|
||||
},
|
||||
onsubmit: function(settings, original) {
|
||||
_enableReloads();
|
||||
},
|
||||
onreset: function(settings, original) {
|
||||
_enableReloads();
|
||||
},
|
||||
tooltip: 'Click to rename...'
|
||||
});
|
||||
|
||||
$(".button-download").click(function(event) {
|
||||
var path = $(this).parent().parent().attr("data-path");
|
||||
var path = $(this).parent().parent().data("path");
|
||||
setTimeout(function() {
|
||||
window.location = "download?path=" + encodeURIComponent(path);
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$(".button-open").click(function(event) {
|
||||
var path = $(this).parent().parent().attr("data-path");
|
||||
var path = $(this).parent().parent().data("path");
|
||||
_reload(path);
|
||||
});
|
||||
|
||||
$(".button-move").click(function(event) {
|
||||
var path = $(this).parent().parent().attr("data-path");
|
||||
var path = $(this).parent().parent().data("path");
|
||||
if (path[path.length - 1] == "/") {
|
||||
path = path.slice(0, path.length - 1);
|
||||
}
|
||||
$("#move-input").attr("data-path", path);
|
||||
$("#move-input").data("path", path);
|
||||
$("#move-input").val(path);
|
||||
$("#move-modal").modal("show");
|
||||
});
|
||||
|
||||
$(".button-delete").click(function(event) {
|
||||
var path = $(this).parent().parent().attr("data-path");
|
||||
var path = $(this).parent().parent().data("path");
|
||||
$.ajax({
|
||||
url: 'delete',
|
||||
type: 'POST',
|
||||
@@ -146,11 +170,9 @@ function _reload(path) {
|
||||
});
|
||||
});
|
||||
|
||||
$(document).scrollTop(scrollPosition);
|
||||
}).always(function() {
|
||||
_reloading = false;
|
||||
if (_pendingReloads.length > 0) {
|
||||
_reload(_pendingReloads.shift());
|
||||
}
|
||||
_enableReloads();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -212,10 +234,16 @@ $(document).ready(function() {
|
||||
|
||||
});
|
||||
|
||||
$("#create-input").keypress(function(event) {
|
||||
if (event.keyCode == ENTER_KEYCODE) {
|
||||
$("#create-confirm").click();
|
||||
};
|
||||
});
|
||||
|
||||
$("#create-modal").on("shown.bs.modal", function(event) {
|
||||
$("#create-input").focus();
|
||||
$("#create-input").select();
|
||||
})
|
||||
});
|
||||
|
||||
$("#create-folder").click(function(event) {
|
||||
$("#create-input").val("Untitled folder");
|
||||
@@ -239,6 +267,12 @@ $(document).ready(function() {
|
||||
}
|
||||
});
|
||||
|
||||
$("#move-input").keypress(function(event) {
|
||||
if (event.keyCode == ENTER_KEYCODE) {
|
||||
$("#move-confirm").click();
|
||||
};
|
||||
});
|
||||
|
||||
$("#move-modal").on("shown.bs.modal", function(event) {
|
||||
$("#move-input").focus();
|
||||
$("#move-input").select();
|
||||
@@ -246,7 +280,7 @@ $(document).ready(function() {
|
||||
|
||||
$("#move-confirm").click(function(event) {
|
||||
$("#move-modal").modal("hide");
|
||||
var oldPath = $("#move-input").attr("data-path");
|
||||
var oldPath = $("#move-input").data("path");
|
||||
var newPath = $("#move-input").val();
|
||||
if ((newPath != "") && (newPath[0] == "/") && (newPath != oldPath)) {
|
||||
$.ajax({
|
||||
|
||||
108
Mac/main.m
108
Mac/main.m
@@ -25,6 +25,8 @@
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#import <libgen.h>
|
||||
|
||||
#import "GCDWebServer.h"
|
||||
|
||||
#import "GCDWebServerDataRequest.h"
|
||||
@@ -37,22 +39,71 @@
|
||||
|
||||
#import "GCDWebUploader.h"
|
||||
|
||||
typedef enum {
|
||||
kMode_WebServer = 0,
|
||||
kMode_HTMLPage,
|
||||
kMode_HTMLForm,
|
||||
kMode_WebDAV,
|
||||
kMode_WebUploader,
|
||||
kMode_StreamingResponse
|
||||
} Mode;
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
BOOL success = NO;
|
||||
int mode = (argc == 2 ? MIN(MAX(atoi(argv[1]), 0), 5) : 0);
|
||||
int result = -1;
|
||||
@autoreleasepool {
|
||||
Mode mode = kMode_WebServer;
|
||||
BOOL recording = NO;
|
||||
NSString* rootDirectory = NSHomeDirectory();
|
||||
NSString* testDirectory = nil;
|
||||
|
||||
if (argc == 1) {
|
||||
fprintf(stdout, "Usage: %s [-mode webServer | htmlPage | htmlForm | webDAV | webUploader | streamingResponse] [-record] [-root directory] [-tests directory]\n\n", basename((char*)argv[0]));
|
||||
} else {
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (argv[i][0] != '-') {
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(argv[i], "-mode") && (i + 1 < argc)) {
|
||||
++i;
|
||||
if (!strcmp(argv[i], "webServer")) {
|
||||
mode = kMode_WebServer;
|
||||
} else if (!strcmp(argv[i], "htmlPage")) {
|
||||
mode = kMode_HTMLPage;
|
||||
} else if (!strcmp(argv[i], "htmlForm")) {
|
||||
mode = kMode_HTMLForm;
|
||||
} else if (!strcmp(argv[i], "webDAV")) {
|
||||
mode = kMode_WebDAV;
|
||||
} else if (!strcmp(argv[i], "webUploader")) {
|
||||
mode = kMode_WebUploader;
|
||||
} else if (!strcmp(argv[i], "streamingResponse")) {
|
||||
mode = kMode_StreamingResponse;
|
||||
}
|
||||
} else if (!strcmp(argv[i], "-record")) {
|
||||
recording = YES;
|
||||
} else if (!strcmp(argv[i], "-root") && (i + 1 < argc)) {
|
||||
++i;
|
||||
rootDirectory = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[i] length:strlen(argv[i])] stringByStandardizingPath];
|
||||
} else if (!strcmp(argv[i], "-tests") && (i + 1 < argc)) {
|
||||
++i;
|
||||
testDirectory = [[[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[i] length:strlen(argv[i])] stringByStandardizingPath];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GCDWebServer* webServer = nil;
|
||||
switch (mode) {
|
||||
|
||||
// Simply serve contents of home directory
|
||||
case 0: {
|
||||
case kMode_WebServer: {
|
||||
fprintf(stdout, "Running in Web Server mode from \"%s\"", [rootDirectory UTF8String]);
|
||||
webServer = [[GCDWebServer alloc] init];
|
||||
[webServer addGETHandlerForBasePath:@"/" directoryPath:NSHomeDirectory() indexFilename:nil cacheAge:0 allowRangeRequests:YES];
|
||||
[webServer addGETHandlerForBasePath:@"/" directoryPath:rootDirectory indexFilename:nil cacheAge:0 allowRangeRequests:YES];
|
||||
break;
|
||||
}
|
||||
|
||||
// Renders a HTML page
|
||||
case 1: {
|
||||
case kMode_HTMLPage: {
|
||||
fprintf(stdout, "Running in HTML Page mode");
|
||||
webServer = [[GCDWebServer alloc] init];
|
||||
[webServer addDefaultHandlerForMethod:@"GET"
|
||||
requestClass:[GCDWebServerRequest class]
|
||||
@@ -65,7 +116,8 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
// Implements an HTML form
|
||||
case 2: {
|
||||
case kMode_HTMLForm: {
|
||||
fprintf(stdout, "Running in HTML Form mode");
|
||||
webServer = [[GCDWebServer alloc] init];
|
||||
[webServer addHandlerForMethod:@"GET"
|
||||
path:@"/"
|
||||
@@ -96,17 +148,23 @@ int main(int argc, const char* argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: {
|
||||
webServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:[[NSFileManager defaultManager] currentDirectoryPath]];
|
||||
// Serve home directory through WebDAV
|
||||
case kMode_WebDAV: {
|
||||
fprintf(stdout, "Running in WebDAV mode from \"%s\"", [rootDirectory UTF8String]);
|
||||
webServer = [[GCDWebDAVServer alloc] initWithUploadDirectory:rootDirectory];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4: {
|
||||
webServer = [[GCDWebUploader alloc] initWithUploadDirectory:[[NSFileManager defaultManager] currentDirectoryPath]];
|
||||
// Serve home directory through web uploader
|
||||
case kMode_WebUploader: {
|
||||
fprintf(stdout, "Running in Web Uploader mode from \"%s\"", [rootDirectory UTF8String]);
|
||||
webServer = [[GCDWebUploader alloc] initWithUploadDirectory:rootDirectory];
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: {
|
||||
// Test streaming responses
|
||||
case kMode_StreamingResponse: {
|
||||
fprintf(stdout, "Running in Streaming Response mode");
|
||||
webServer = [[GCDWebServer alloc] init];
|
||||
[webServer addHandlerForMethod:@"GET"
|
||||
path:@"/"
|
||||
@@ -130,10 +188,30 @@ int main(int argc, const char* argv[]) {
|
||||
}
|
||||
|
||||
}
|
||||
success = [webServer runWithPort:8080];
|
||||
#if !__has_feature(objc_arc)
|
||||
[webServer release];
|
||||
#if __has_feature(objc_arc)
|
||||
fprintf(stdout, " (ARC is ON)\n");
|
||||
#else
|
||||
fprintf(stdout, " (ARC is OFF)\n");
|
||||
#endif
|
||||
|
||||
if (webServer) {
|
||||
if (testDirectory) {
|
||||
fprintf(stdout, "<RUNNING TESTS FROM \"%s\">\n\n", [testDirectory UTF8String]);
|
||||
result = (int)[webServer runTestsInDirectory:testDirectory withPort:8080];
|
||||
} else {
|
||||
if (recording) {
|
||||
fprintf(stdout, "<RECORDING ENABLED>\n");
|
||||
webServer.recordingEnabled = YES;
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
if ([webServer runWithPort:8080]) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
#if !__has_feature(objc_arc)
|
||||
[webServer release];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return success ? 0 : -1;
|
||||
return result;
|
||||
}
|
||||
|
||||
59
README.md
59
README.md
@@ -1,8 +1,10 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
GCDWebServer is a lightweight GCD based HTTP 1.1 server designed to be embedded in Mac & iOS apps. It was written from scratch with the following goals in mind:
|
||||
* Easy to use and understand architecture with only 4 core classes: server, connection, request and response
|
||||
[](https://travis-ci.org/swisspol/GCDWebServer)
|
||||
|
||||
GCDWebServer is a modern and lightweight GCD based HTTP 1.1 server designed to be embedded in Mac & iOS apps. It was written from scratch with the following goals in mind:
|
||||
* Easy to use and understand architecture with only 4 core classes: server, connection, request and response (see "Understanding GCDWebServer's Architecture" below)
|
||||
* Well designed API for easy integration and customization
|
||||
* Entirely built with an event-driven design using [Grand Central Dispatch](http://en.wikipedia.org/wiki/Grand_Central_Dispatch) for maximal performance and concurrency
|
||||
* No dependencies on third-party source code
|
||||
@@ -14,10 +16,11 @@ Extra built-in features:
|
||||
* [JSON](http://www.json.org/) parsing and serialization for request and response HTTP bodies
|
||||
* [Chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding) for request and response HTTP bodies
|
||||
* [HTTP compression](https://en.wikipedia.org/wiki/HTTP_compression) with gzip for request and response HTTP bodies
|
||||
* [HTTP range](https://en.wikipedia.org/wiki/Byte_serving) support for requests of local files
|
||||
|
||||
Included extensions:
|
||||
* [GCDWebUploader](GCDWebUploader/GCDWebUploader.h): subclass of GCDWebServer that implements an interface for uploading and downloading files from an iOS app's sandbox using a web browser
|
||||
* [GCDWebDAVServer](GCDWebDAVServer/GCDWebDAVServer.h): subclass of GCDWebServer that implements a class 1 [WebDAV](https://en.wikipedia.org/wiki/WebDAV) server (with partial class 2 support for OS X Finder)
|
||||
* [GCDWebUploader](GCDWebUploader/GCDWebUploader.h): subclass of ```GCDWebServer``` that implements an interface for uploading and downloading files from an iOS app's sandbox using a web browser
|
||||
* [GCDWebDAVServer](GCDWebDAVServer/GCDWebDAVServer.h): subclass of ```GCDWebServer``` that implements a class 1 [WebDAV](https://en.wikipedia.org/wiki/WebDAV) server (with partial class 2 support for OS X Finder)
|
||||
|
||||
What's not available out of the box but can be implemented on top of the API:
|
||||
* Authentication like [Basic Authentication](https://en.wikipedia.org/wiki/Basic_access_authentication)
|
||||
@@ -40,11 +43,19 @@ Alternatively, you can install GCDWebServer using [CocoaPods](http://cocoapods.o
|
||||
```
|
||||
pod "GCDWebServer", "~> 2.0"
|
||||
```
|
||||
If you want to use GCDWebUploader, use this line instead:
|
||||
```
|
||||
pod "GCDWebServer/WebUploader", "~> 2.0"
|
||||
```
|
||||
Or this line for GCDWebDAVServer:
|
||||
```
|
||||
pod "GCDWebServer/WebDAV", "~> 2.0"
|
||||
```
|
||||
|
||||
Hello World
|
||||
===========
|
||||
|
||||
This code snippet shows how to implement a custom HTTP server that runs on port 8080 and returns a "Hello World" HTML page to any request — since GCDWebServer uses GCD blocks to handle requests, no subclassing or delegates are needed:
|
||||
This code snippet shows how to implement a custom HTTP server that runs on port 8080 and returns a "Hello World" HTML page to any request — since GCDWebServer uses GCD blocks to handle requests, no subclassing or delegates are needed, which results in very clean code:
|
||||
|
||||
```objectivec
|
||||
#import "GCDWebServer.h"
|
||||
@@ -55,7 +66,7 @@ int main(int argc, const char* argv[]) {
|
||||
// Create server
|
||||
GCDWebServer* webServer = [[GCDWebServer alloc] init];
|
||||
|
||||
// Add a handler to respond to requests on any URL
|
||||
// Add a handler to respond to GET requests on any URL
|
||||
[webServer addDefaultHandlerForMethod:@"GET"
|
||||
requestClass:[GCDWebServerRequest class]
|
||||
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
|
||||
@@ -78,7 +89,7 @@ int main(int argc, const char* argv[]) {
|
||||
Web Based Uploads in iOS Apps
|
||||
=============================
|
||||
|
||||
GCDWebUploader is a subclass of GCDWebServer that provides a ready-to-use HTML 5 file uploader & downloader. This lets users upload, download, delete files and create directories from a directory inside your iOS app's sandbox using a clean user interface in their web browser.
|
||||
GCDWebUploader is a subclass of ```GCDWebServer``` that provides a ready-to-use HTML 5 file uploader & downloader. This lets users upload, download, delete files and create directories from a directory inside your iOS app's sandbox using a clean user interface in their web browser.
|
||||
|
||||
Simply instantiate and run a GCDWebUploader instance then visit http://{YOUR-IOS-DEVICE-IP-ADDRESS}/ from your web browser:
|
||||
|
||||
@@ -97,7 +108,7 @@ Simply instantiate and run a GCDWebUploader instance then visit http://{YOUR-IOS
|
||||
WebDAV Server in iOS Apps
|
||||
=========================
|
||||
|
||||
GCDWebDAVServer is a subclass of GCDWebServer that provides a class 1 compliant [WebDAV](https://en.wikipedia.org/wiki/WebDAV) server. This lets users upload, download, delete files and create directories from a directory inside your iOS app's sandbox using any WebDAV client like [Transmit](https://panic.com/transmit/) (Mac), [ForkLift](http://binarynights.com/forklift/) (Mac) or [CyberDuck](http://cyberduck.io/) (Mac / Windows).
|
||||
GCDWebDAVServer is a subclass of ```GCDWebServer``` that provides a class 1 compliant [WebDAV](https://en.wikipedia.org/wiki/WebDAV) server. This lets users upload, download, delete files and create directories from a directory inside your iOS app's sandbox using any WebDAV client like [Transmit](https://panic.com/transmit/) (Mac), [ForkLift](http://binarynights.com/forklift/) (Mac) or [CyberDuck](http://cyberduck.io/) (Mac / Windows).
|
||||
|
||||
GCDWebDAVServer should also work with the [OS X Finder](http://support.apple.com/kb/PH13859) as it is partially class 2 compliant (but only when the client is the OS X WebDAV implementation).
|
||||
|
||||
@@ -118,7 +129,7 @@ Simply instantiate and run a GCDWebDAVServer instance then connect to http://{YO
|
||||
Serving a Static Website
|
||||
========================
|
||||
|
||||
GCDWebServer includes a built-in handler that can recursively serve a directory (it also lets you control how the "Cache-Control" header should be set):
|
||||
GCDWebServer includes a built-in handler that can recursively serve a directory (it also lets you control how the ["Cache-Control"](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9) header should be set):
|
||||
|
||||
```objectivec
|
||||
#import "GCDWebServer.h"
|
||||
@@ -139,20 +150,20 @@ int main(int argc, const char* argv[]) {
|
||||
Using GCDWebServer
|
||||
==================
|
||||
|
||||
You start by creating an instance of the 'GCDWebServer' class. Note that you can have multiple web servers running in the same app as long as they listen on different ports.
|
||||
You start by creating an instance of the ```GCDWebServer``` class. Note that you can have multiple web servers running in the same app as long as they listen on different ports.
|
||||
|
||||
Then you add one or more "handlers" to the server: each handler gets a chance to handle an incoming web request and provide a response. Handlers are called in a LIFO queue, so the latest added handler overrides any previously added ones.
|
||||
|
||||
Finally you start the server on a given port.
|
||||
|
||||
Understanding GCDWebServer Architecture
|
||||
=======================================
|
||||
Understanding GCDWebServer's Architecture
|
||||
=========================================
|
||||
|
||||
GCDWebServer is made of only 4 core classes:
|
||||
* 'GCDWebServer' manages the socket that listens for new HTTP connections and the list of handlers used by the server.
|
||||
* 'GCDWebServerConnection' 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 exposed so you can subclass it to override some hooks.
|
||||
* 'GCDWebServerRequest' is created by the 'GCDWebServerConnection' instance after HTTP headers have been received. It wraps the request and handles the HTTP body if any. GCDWebServer comes with several subclasses of 'GCDWebServerRequest' to handle common cases like storing the body in memory or stream it to a file on disk. See [GCDWebServerRequest.h](CGDWebServer/GCDWebServerRequest.h) for the full list.
|
||||
* 'GCDWebServerResponse' is created by the request handler and wraps the response HTTP headers and optional body. GCDWebServer provides several subclasses of 'GCDWebServerResponse' to handle common cases like HTML text in memory or streaming a file from disk. See [GCDWebServerResponse.h](CGDWebServer/GCDWebServerResponse.h) for the full list.
|
||||
GCDWebServer's architecture consists of only 4 core classes:
|
||||
* [GCDWebServer](GCDWebServer/Core/GCDWebServer.h) manages the socket that listens for new HTTP connections and the list of handlers used by the server.
|
||||
* [GCDWebServerConnection](GCDWebServer/Core/GCDWebServerConnection.h) 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 exposed so you can subclass it to override some hooks.
|
||||
* [GCDWebServerRequest](GCDWebServer/Core/GCDWebServerRequest.h) is created by the ```GCDWebServerConnection``` instance after HTTP headers have been received. It wraps the request and handles the HTTP body if any. GCDWebServer comes with [several subclasses](GCDWebServer/Requests) of ```GCDWebServerRequest``` to handle common cases like storing the body in memory or stream it to a file on disk.
|
||||
* [GCDWebServerResponse](GCDWebServer/Core/GCDWebServerResponse.h) is created by the request handler and wraps the response HTTP headers and optional body. GCDWebServer comes with [several subclasses](GCDWebServer/Responses) of ```GCDWebServerResponse``` to handle common cases like HTML text in memory or streaming a file from disk.
|
||||
|
||||
Implementing Handlers
|
||||
=====================
|
||||
@@ -160,15 +171,15 @@ Implementing Handlers
|
||||
GCDWebServer relies on "handlers" to process incoming web requests and generating responses. Handlers are implemented with GCD blocks which makes it very easy to provide your owns. However, they are executed on arbitrary threads within GCD so __special attention must be paid to thread-safety and re-entrancy__.
|
||||
|
||||
Handlers require 2 GCD blocks:
|
||||
* The 'GCDWebServerMatchBlock' is called on every handler added to the 'GCDWebServer' instance whenever a web request has started (i.e. HTTP headers have been received). It is passed the basic info for the web request (HTTP method, URL, headers...) and must decide if it wants to handle it or not. If yes, it must return a 'GCDWebServerRequest' instance (see above). Otherwise, it simply returns nil.
|
||||
* The 'GCDWebServerProcessBlock' is called after the web request has been fully received and is passed the 'GCDWebServerRequest' instance created at the previous step. It must return a 'GCDWebServerResponse' instance (see above) or nil on error.
|
||||
* The ```GCDWebServerMatchBlock``` is called on every handler added to the ```GCDWebServer``` instance whenever a web request has started (i.e. HTTP headers have been received). It is passed the basic info for the web request (HTTP method, URL, headers...) and must decide if it wants to handle it or not. If yes, it must return a ```GCDWebServerRequest``` instance (see above). Otherwise, it simply returns nil.
|
||||
* The ```GCDWebServerProcessBlock``` is called after the web request has been fully received and is passed the ```GCDWebServerRequest``` instance created at the previous step. It must return a ```GCDWebServerResponse``` instance (see above) or nil on error.
|
||||
|
||||
Note that most methods on 'GCDWebServer' to add handlers only require the 'GCDWebServerProcessBlock' as they already provide a built-in 'GCDWebServerMatchBlock' e.g. to match a URL path with a Regex.
|
||||
Note that most methods on ```GCDWebServer``` to add handlers only require the ```GCDWebServerProcessBlock``` as they already provide a built-in ```GCDWebServerMatchBlock``` e.g. to match a URL path with a Regex.
|
||||
|
||||
Advanced Example 1: Implementing HTTP Redirects
|
||||
===============================================
|
||||
|
||||
Here's an example handler that redirects "/" to "/index.html" using the convenience method on 'GCDWebServerResponse' (it sets the HTTP status code and 'Location' header automatically):
|
||||
Here's an example handler that redirects "/" to "/index.html" using the convenience method on ```GCDWebServerResponse``` (it sets the HTTP status code and "Location" header automatically):
|
||||
|
||||
```objectivec
|
||||
[self addHandlerForMethod:@"GET"
|
||||
@@ -186,8 +197,8 @@ Advanced Example 2: Implementing Forms
|
||||
======================================
|
||||
|
||||
To implement an HTTP form, you need a pair of handlers:
|
||||
* The GET handler does not expect any body in the HTTP request and therefore uses the 'GCDWebServerRequest' class. The handler generates a response containing a simple HTML form.
|
||||
* The POST handler expects the form values to be in the body of the HTTP request and percent-encoded. Fortunately, GCDWebServer provides the request class 'GCDWebServerURLEncodedFormRequest' which can automatically parse such bodies. The handler simply echoes back the value from the user submitted form.
|
||||
* The GET handler does not expect any body in the HTTP request and therefore uses the ```GCDWebServerRequest``` class. The handler generates a response containing a simple HTML form.
|
||||
* The POST handler expects the form values to be in the body of the HTTP request and percent-encoded. Fortunately, GCDWebServer provides the request class ```GCDWebServerURLEncodedFormRequest``` which can automatically parse such bodies. The handler simply echoes back the value from the user submitted form.
|
||||
|
||||
```objectivec
|
||||
[webServer addHandlerForMethod:@"GET"
|
||||
@@ -222,7 +233,7 @@ To implement an HTTP form, you need a pair of handlers:
|
||||
Advanced Example 3: Serving a Dynamic Website
|
||||
=============================================
|
||||
|
||||
GCDWebServer provides an extension to the 'GCDWebServerDataResponse' class that can return HTML content generated from a template and a set of variables (using the format '%variable%'). It is a very basic template system and is really intended as a starting point to building more advanced template systems by subclassing 'GCDWebServerResponse'.
|
||||
GCDWebServer provides an extension to the ```GCDWebServerDataResponse``` class that can return HTML content generated from a template and a set of variables (using the format ```%variable%```). It is a very basic template system and is really intended as a starting point to building more advanced template systems by subclassing ```GCDWebServerResponse```.
|
||||
|
||||
Assuming you have a website directory in your app containing HTML template files along with the corresponding CSS, scripts and images, it's pretty easy to turn it into a dynamic website:
|
||||
|
||||
|
||||
42
Run-Tests.sh
Executable file
42
Run-Tests.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
TARGET="GCDWebServer (Mac)"
|
||||
CONFIGURATION="Release"
|
||||
|
||||
MRC_BUILD_DIR="/tmp/GCDWebServer-MRC"
|
||||
MRC_PRODUCT="$MRC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
|
||||
ARC_BUILD_DIR="/tmp/GCDWebServer-ARC"
|
||||
ARC_PRODUCT="$ARC_BUILD_DIR/$CONFIGURATION/GCDWebServer"
|
||||
|
||||
PAYLOAD_ZIP="Tests/Payload.zip"
|
||||
PAYLOAD_DIR="/tmp/GCDWebServer"
|
||||
|
||||
function runTests {
|
||||
rm -rf "$PAYLOAD_DIR"
|
||||
ditto -x -k "$PAYLOAD_ZIP" "$PAYLOAD_DIR"
|
||||
TZ=GMT find "$PAYLOAD_DIR" -type d -exec SetFile -d "1/1/2014 00:00:00" -m "1/1/2014 00:00:00" '{}' \; # ZIP archives do not preserve directories dates
|
||||
logLevel=2 $1 -mode "$2" -root "$PAYLOAD_DIR/Payload" -tests "$3"
|
||||
}
|
||||
|
||||
# Build in manual memory management mode
|
||||
rm -rf "MRC_BUILD_DIR"
|
||||
xcodebuild -target "$TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$MRC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=NO" > /dev/null
|
||||
|
||||
# Build in ARC mode
|
||||
rm -rf "ARC_BUILD_DIR"
|
||||
xcodebuild -target "$TARGET" -configuration "$CONFIGURATION" build "SYMROOT=$ARC_BUILD_DIR" "CLANG_ENABLE_OBJC_ARC=YES" > /dev/null
|
||||
|
||||
# Run tests
|
||||
runTests $MRC_PRODUCT "webServer" "Tests/WebServer"
|
||||
runTests $ARC_PRODUCT "webServer" "Tests/WebServer"
|
||||
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Transmit"
|
||||
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Transmit"
|
||||
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Cyberduck"
|
||||
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Cyberduck"
|
||||
runTests $MRC_PRODUCT "webDAV" "Tests/WebDAV-Finder"
|
||||
runTests $ARC_PRODUCT "webDAV" "Tests/WebDAV-Finder"
|
||||
runTests $MRC_PRODUCT "webUploader" "Tests/WebUploader"
|
||||
runTests $ARC_PRODUCT "webUploader" "Tests/WebUploader"
|
||||
|
||||
# Done
|
||||
echo "\nAll tests completed successfully!"
|
||||
BIN
Tests/Payload.zip
Normal file
BIN
Tests/Payload.zip
Normal file
Binary file not shown.
6
Tests/WebDAV-Cyberduck/001-200.response
Executable file
6
Tests/WebDAV-Cyberduck/001-200.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:42 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/001-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/001-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
14
Tests/WebDAV-Cyberduck/002-207.response
Executable file
14
Tests/WebDAV-Cyberduck/002-207.response
Executable file
@@ -0,0 +1,14 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1106
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:42 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/002-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/002-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
12
Tests/WebDAV-Cyberduck/003-207.response
Executable file
12
Tests/WebDAV-Cyberduck/003-207.response
Executable file
@@ -0,0 +1,12 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 700
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:47 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/PDF%20Reports/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2013-05-01T12:01:13+00:00</D:creationdate><D:getlastmodified>Wed, 01 May 2013 12:01:13 GMT</D:getlastmodified><D:getcontentlength>181952</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/003-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/003-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND /PDF%20Reports/ HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
13
Tests/WebDAV-Cyberduck/004-207.response
Executable file
13
Tests/WebDAV-Cyberduck/004-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 998
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:47 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/images/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images/capable_green_ipad_l.png</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T21:46:56+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 21:46:56 GMT</D:getlastmodified><D:getcontentlength>116066</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images/hero_mba_11.jpg</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T21:51:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 21:51:14 GMT</D:getlastmodified><D:getcontentlength>106799</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/004-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/004-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND /images/ HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/005-200.response
Executable file
6
Tests/WebDAV-Cyberduck/005-200.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:51 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/005-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/005-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
7
Tests/WebDAV-Cyberduck/006-404.response
Executable file
7
Tests/WebDAV-Cyberduck/006-404.response
Executable file
@@ -0,0 +1,7 @@
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Length: 204
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:51 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/006-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/006-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD /Copy%20%284%3A11%3A14%2C%209%3A52%20PM%29.txt HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/007-201.response
Executable file
6
Tests/WebDAV-Cyberduck/007-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:51 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/007-COPY.request
Executable file
8
Tests/WebDAV-Cyberduck/007-COPY.request
Executable file
@@ -0,0 +1,8 @@
|
||||
COPY /Copy.txt HTTP/1.1
|
||||
Destination: http://localhost:8080/Copy%20%284%3A11%3A14%2C%209%3A52%20PM%29.txt
|
||||
Overwrite: T
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
15
Tests/WebDAV-Cyberduck/008-207.response
Executable file
15
Tests/WebDAV-Cyberduck/008-207.response
Executable file
@@ -0,0 +1,15 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1448
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:51 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy%20(4:11:14,%209:52%20PM).txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/008-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/008-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/009-200.response
Executable file
6
Tests/WebDAV-Cyberduck/009-200.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:52:59 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/009-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/009-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
BIN
Tests/WebDAV-Cyberduck/010-200.response
Executable file
BIN
Tests/WebDAV-Cyberduck/010-200.response
Executable file
Binary file not shown.
6
Tests/WebDAV-Cyberduck/010-GET.request
Executable file
6
Tests/WebDAV-Cyberduck/010-GET.request
Executable file
@@ -0,0 +1,6 @@
|
||||
GET /images/capable_green_ipad_l.png HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
13
Tests/WebDAV-Cyberduck/011-207.response
Executable file
13
Tests/WebDAV-Cyberduck/011-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 998
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:07 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/images/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images/capable_green_ipad_l.png</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T21:46:56+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 21:46:56 GMT</D:getlastmodified><D:getcontentlength>116066</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/images/hero_mba_11.jpg</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T21:51:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 21:51:14 GMT</D:getlastmodified><D:getcontentlength>106799</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/011-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/011-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND /images/ HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/012-204.response
Executable file
6
Tests/WebDAV-Cyberduck/012-204.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:07 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/012-DELETE.request
Executable file
6
Tests/WebDAV-Cyberduck/012-DELETE.request
Executable file
@@ -0,0 +1,6 @@
|
||||
DELETE /images/capable_green_ipad_l.png HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/013-204.response
Executable file
6
Tests/WebDAV-Cyberduck/013-204.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:07 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/013-DELETE.request
Executable file
6
Tests/WebDAV-Cyberduck/013-DELETE.request
Executable file
@@ -0,0 +1,6 @@
|
||||
DELETE /images/hero_mba_11.jpg HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/014-204.response
Executable file
6
Tests/WebDAV-Cyberduck/014-204.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 204 No Content
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:07 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/014-DELETE.request
Executable file
6
Tests/WebDAV-Cyberduck/014-DELETE.request
Executable file
@@ -0,0 +1,6 @@
|
||||
DELETE /images/ HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
14
Tests/WebDAV-Cyberduck/015-207.response
Executable file
14
Tests/WebDAV-Cyberduck/015-207.response
Executable file
@@ -0,0 +1,14 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1214
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:07 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy%20(4:11:14,%209:52%20PM).txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/015-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/015-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/016-201.response
Executable file
6
Tests/WebDAV-Cyberduck/016-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:13 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/016-MOVE.request
Executable file
8
Tests/WebDAV-Cyberduck/016-MOVE.request
Executable file
@@ -0,0 +1,8 @@
|
||||
MOVE /Copy%20%284%3A11%3A14%2C%209%3A52%20PM%29.txt HTTP/1.1
|
||||
Destination: http://localhost:8080/Test.txt
|
||||
Overwrite: T
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
14
Tests/WebDAV-Cyberduck/017-207.response
Executable file
14
Tests/WebDAV-Cyberduck/017-207.response
Executable file
@@ -0,0 +1,14 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1189
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:13 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Test.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/017-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/017-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/018-201.response
Executable file
6
Tests/WebDAV-Cyberduck/018-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:14 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/018-MOVE.request
Executable file
8
Tests/WebDAV-Cyberduck/018-MOVE.request
Executable file
@@ -0,0 +1,8 @@
|
||||
MOVE /Test.txt HTTP/1.1
|
||||
Destination: http://localhost:8080/PDF%20Reports/Test.txt
|
||||
Overwrite: T
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
13
Tests/WebDAV-Cyberduck/019-207.response
Executable file
13
Tests/WebDAV-Cyberduck/019-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 872
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:14 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/019-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/019-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
13
Tests/WebDAV-Cyberduck/020-207.response
Executable file
13
Tests/WebDAV-Cyberduck/020-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1031
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:14 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/PDF%20Reports/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports/Apple%20Economic%20Impact%20on%20Cupertino.pdf</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2013-05-01T12:01:13+00:00</D:creationdate><D:getlastmodified>Wed, 01 May 2013 12:01:13 GMT</D:getlastmodified><D:getcontentlength>181952</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports/Test.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/020-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/020-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND /PDF%20Reports/ HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/021-200.response
Executable file
6
Tests/WebDAV-Cyberduck/021-200.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 200 OK
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:22 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/021-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/021-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
7
Tests/WebDAV-Cyberduck/022-404.response
Executable file
7
Tests/WebDAV-Cyberduck/022-404.response
Executable file
@@ -0,0 +1,7 @@
|
||||
HTTP/1.1 404 Not Found
|
||||
Content-Length: 190
|
||||
Content-Type: text/html; charset=utf-8
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:22 GMT
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/022-HEAD.request
Executable file
6
Tests/WebDAV-Cyberduck/022-HEAD.request
Executable file
@@ -0,0 +1,6 @@
|
||||
HEAD /Test%20File.txt HTTP/1.1
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/023-201.response
Executable file
6
Tests/WebDAV-Cyberduck/023-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:22 GMT
|
||||
|
||||
11
Tests/WebDAV-Cyberduck/023-PUT.request
Executable file
11
Tests/WebDAV-Cyberduck/023-PUT.request
Executable file
@@ -0,0 +1,11 @@
|
||||
PUT /Test%20File.txt HTTP/1.1
|
||||
Content-Length: 21
|
||||
Content-Type: text/plain
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
X-GCDWebServer-CreationDate: 2014-04-12T04:53:22+00:00
|
||||
X-GCDWebServer-ModifiedDate: Sat, 12 Apr 2014 04:53:22 GMT
|
||||
|
||||
Nothing to see here!
|
||||
14
Tests/WebDAV-Cyberduck/024-207.response
Executable file
14
Tests/WebDAV-Cyberduck/024-207.response
Executable file
@@ -0,0 +1,14 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1195
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:22 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Test%20File.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-12T04:53:22+00:00</D:creationdate><D:getlastmodified>Sat, 12 Apr 2014 04:53:22 GMT</D:getlastmodified><D:getcontentlength>21</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/024-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/024-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/025-201.response
Executable file
6
Tests/WebDAV-Cyberduck/025-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:35 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/025-MKCOL.request
Executable file
8
Tests/WebDAV-Cyberduck/025-MKCOL.request
Executable file
@@ -0,0 +1,8 @@
|
||||
MKCOL /Text%20Files/ HTTP/1.1
|
||||
Content-Length: 0
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
X-GCDWebServer-CreationDate: 2014-04-12T04:53:35+00:00
|
||||
|
||||
15
Tests/WebDAV-Cyberduck/026-207.response
Executable file
15
Tests/WebDAV-Cyberduck/026-207.response
Executable file
@@ -0,0 +1,15 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 1435
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:35 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Test%20File.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-12T04:53:22+00:00</D:creationdate><D:getlastmodified>Sat, 12 Apr 2014 04:53:22 GMT</D:getlastmodified><D:getcontentlength>21</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Text%20Files</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-04-12T04:53:35+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/026-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/026-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
11
Tests/WebDAV-Cyberduck/027-207.response
Executable file
11
Tests/WebDAV-Cyberduck/027-207.response
Executable file
@@ -0,0 +1,11 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 327
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:36 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/Text%20Files/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-04-12T04:53:35+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/027-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/027-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND /Text%20Files/ HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
6
Tests/WebDAV-Cyberduck/028-201.response
Executable file
6
Tests/WebDAV-Cyberduck/028-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:39 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/028-MOVE.request
Executable file
8
Tests/WebDAV-Cyberduck/028-MOVE.request
Executable file
@@ -0,0 +1,8 @@
|
||||
MOVE /Test%20File.txt HTTP/1.1
|
||||
Destination: http://localhost:8080/Text%20Files/Test%20File.txt
|
||||
Overwrite: T
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
6
Tests/WebDAV-Cyberduck/029-201.response
Executable file
6
Tests/WebDAV-Cyberduck/029-201.response
Executable file
@@ -0,0 +1,6 @@
|
||||
HTTP/1.1 201 Created
|
||||
Cache-Control: no-cache
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:39 GMT
|
||||
|
||||
8
Tests/WebDAV-Cyberduck/029-MOVE.request
Executable file
8
Tests/WebDAV-Cyberduck/029-MOVE.request
Executable file
@@ -0,0 +1,8 @@
|
||||
MOVE /Copy.txt HTTP/1.1
|
||||
Destination: http://localhost:8080/Text%20Files/Copy.txt
|
||||
Overwrite: T
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
13
Tests/WebDAV-Cyberduck/030-207.response
Executable file
13
Tests/WebDAV-Cyberduck/030-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 795
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:39 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/PDF%20Reports</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-01-01T00:00:00+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Text%20Files</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-04-12T04:53:35+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
10
Tests/WebDAV-Cyberduck/030-PROPFIND.request
Executable file
10
Tests/WebDAV-Cyberduck/030-PROPFIND.request
Executable file
@@ -0,0 +1,10 @@
|
||||
PROPFIND / HTTP/1.1
|
||||
Depth: 1
|
||||
Content-Type: text/xml; charset=utf-8
|
||||
Content-Length: 99
|
||||
Host: localhost:8080
|
||||
Connection: Keep-Alive
|
||||
User-Agent: Cyberduck/4.4.3 (Mac OS X/10.9.2) (x86_64)
|
||||
Accept-Encoding: gzip,deflate
|
||||
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><propfind xmlns="DAV:"><allprop/></propfind>
|
||||
13
Tests/WebDAV-Cyberduck/031-207.response
Executable file
13
Tests/WebDAV-Cyberduck/031-207.response
Executable file
@@ -0,0 +1,13 @@
|
||||
HTTP/1.1 207 Multi-Status
|
||||
Cache-Control: no-cache
|
||||
Content-Length: 993
|
||||
Content-Type: application/xml; charset="utf-8"
|
||||
Connection: Close
|
||||
Server: GCDWebDAVServer
|
||||
Date: Sat, 12 Apr 2014 04:53:39 GMT
|
||||
|
||||
<?xml version="1.0" encoding="utf-8" ?><D:multistatus xmlns:D="DAV:">
|
||||
<D:response><D:href>/Text%20Files/</D:href><D:propstat><D:prop><D:resourcetype><D:collection/></D:resourcetype><D:creationdate>2014-04-12T04:53:35+00:00</D:creationdate></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Text%20Files/Copy.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-10T11:10:14+00:00</D:creationdate><D:getlastmodified>Thu, 10 Apr 2014 11:10:14 GMT</D:getlastmodified><D:getcontentlength>271</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
<D:response><D:href>/Text%20Files/Test%20File.txt</D:href><D:propstat><D:prop><D:resourcetype/><D:creationdate>2014-04-12T04:53:22+00:00</D:creationdate><D:getlastmodified>Sat, 12 Apr 2014 04:53:22 GMT</D:getlastmodified><D:getcontentlength>21</D:getcontentlength></D:prop><D:status>HTTP/1.1 200 OK</D:status></D:propstat></D:response>
|
||||
</D:multistatus>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user