chore: Initial clean commit
- Removed YuMi/Library/ (138 MB, not tracked) - Removed YuMi/Resources/ (23 MB, not tracked) - Removed old version assets (566 files, not tracked) - Excluded Pods/, xcuserdata/ and other build artifacts - Clean repository optimized for company server deployment
This commit is contained in:
208
YuMi/Tools/CocoaHttpServer/MyHTTPConnection.m
Executable file
208
YuMi/Tools/CocoaHttpServer/MyHTTPConnection.m
Executable file
@@ -0,0 +1,208 @@
|
||||
|
||||
#import "MyHTTPConnection.h"
|
||||
#import "HTTPMessage.h"
|
||||
#import "HTTPDataResponse.h"
|
||||
#import "DDNumber.h"
|
||||
#import "HTTPLogging.h"
|
||||
|
||||
#import "MultipartFormDataParser.h"
|
||||
#import "MultipartMessageHeaderField.h"
|
||||
#import "HTTPDynamicFileResponse.h"
|
||||
#import "HTTPFileResponse.h"
|
||||
|
||||
|
||||
// Log levels : off, error, warn, info, verbose
|
||||
// Other flags: trace
|
||||
static const int httpLogLevel = HTTP_LOG_LEVEL_VERBOSE; // | HTTP_LOG_FLAG_TRACE;
|
||||
|
||||
|
||||
/**
|
||||
* All we have to do is override appropriate methods in HTTPConnection.
|
||||
**/
|
||||
|
||||
@implementation MyHTTPConnection
|
||||
|
||||
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path {
|
||||
|
||||
HTTPLogTrace();
|
||||
|
||||
// Add support for POST
|
||||
|
||||
if ([method isEqualToString:@"POST"])
|
||||
{
|
||||
if ([path isEqualToString:@"/upload.html"])
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
return [super supportsMethod:method atPath:path];
|
||||
}
|
||||
|
||||
- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path {
|
||||
|
||||
HTTPLogTrace();
|
||||
|
||||
// Inform HTTP server that we expect a body to accompany a POST request
|
||||
|
||||
if([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.html"]) {
|
||||
// here we need to make sure, boundary is set in header
|
||||
NSString* contentType = [request headerField:@"Content-Type"];
|
||||
NSUInteger paramsSeparator = [contentType rangeOfString:@";"].location;
|
||||
if( NSNotFound == paramsSeparator ) {
|
||||
return NO;
|
||||
}
|
||||
if( paramsSeparator >= contentType.length - 1 ) {
|
||||
return NO;
|
||||
}
|
||||
NSString* type = [contentType substringToIndex:paramsSeparator];
|
||||
if( ![type isEqualToString:@"multipart/form-data"] ) {
|
||||
// we expect multipart/form-data content type
|
||||
return NO;
|
||||
}
|
||||
|
||||
// enumerate all params in content-type, and find boundary there
|
||||
NSArray* params = [[contentType substringFromIndex:paramsSeparator + 1] componentsSeparatedByString:@";"];
|
||||
for( NSString* param in params ) {
|
||||
paramsSeparator = [param rangeOfString:@"="].location;
|
||||
if( (NSNotFound == paramsSeparator) || paramsSeparator >= param.length - 1 ) {
|
||||
continue;
|
||||
}
|
||||
NSString* paramName = [param substringWithRange:NSMakeRange(1, paramsSeparator-1)];
|
||||
NSString* paramValue = [param substringFromIndex:paramsSeparator+1];
|
||||
|
||||
if( [paramName isEqualToString: @"boundary"] ) {
|
||||
// let's separate the boundary from content-type, to make it more handy to handle
|
||||
[request setHeaderField:@"boundary" value:paramValue];
|
||||
}
|
||||
}
|
||||
// check if boundary specified
|
||||
if( nil == [request headerField:@"boundary"] ) {
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
return [super expectsRequestBodyFromMethod:method atPath:path];
|
||||
}
|
||||
|
||||
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path {
|
||||
|
||||
HTTPLogTrace();
|
||||
|
||||
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.html"]) {
|
||||
|
||||
// this method will generate response with links to uploaded file
|
||||
NSMutableString* filesStr = [[NSMutableString alloc] init];
|
||||
|
||||
for( NSString* filePath in uploadedFiles ) {
|
||||
//generate links
|
||||
[filesStr appendFormat:@"<a href=\"%@\"> %@ </a><br/>",filePath, [filePath lastPathComponent]];
|
||||
}
|
||||
NSString* templatePath = [[config documentRoot] stringByAppendingPathComponent:@"upload.html"];
|
||||
NSDictionary* replacementDict = [NSDictionary dictionaryWithObject:filesStr forKey:@"MyFiles"];
|
||||
// use dynamic file response to apply our links to response template
|
||||
return [[HTTPDynamicFileResponse alloc] initWithFilePath:templatePath forConnection:self separator:@"%" replacementDictionary:replacementDict];
|
||||
}
|
||||
if( [method isEqualToString:@"GET"] && [path hasPrefix:@"/upload/"] ) {
|
||||
// let download the uploaded files
|
||||
return [[HTTPFileResponse alloc] initWithFilePath: [[config documentRoot] stringByAppendingString:path] forConnection:self];
|
||||
}
|
||||
|
||||
return [super httpResponseForMethod:method URI:path];
|
||||
}
|
||||
|
||||
- (void)prepareForBodyWithSize:(UInt64)contentLength {
|
||||
HTTPLogTrace();
|
||||
|
||||
// set up mime parser
|
||||
NSString* boundary = [request headerField:@"boundary"];
|
||||
parser = [[MultipartFormDataParser alloc] initWithBoundary:boundary formEncoding:NSUTF8StringEncoding];
|
||||
parser.delegate = self;
|
||||
|
||||
uploadedFiles = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (void)processBodyData:(NSData *)postDataChunk {
|
||||
HTTPLogTrace();
|
||||
// append data to the parser. It will invoke callbacks to let us handle
|
||||
// parsed data.
|
||||
[parser appendData:postDataChunk];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------
|
||||
#pragma mark multipart form data parser delegate
|
||||
|
||||
|
||||
- (void) processStartOfPartWithHeader:(MultipartMessageHeader*) header {
|
||||
// in this sample, we are not interested in parts, other then file parts.
|
||||
// check content disposition to find out filename
|
||||
|
||||
MultipartMessageHeaderField* disposition = [header.fields objectForKey:@"Content-Disposition"];
|
||||
NSString* filename = [[disposition.params objectForKey:@"filename"] lastPathComponent];
|
||||
|
||||
if ( (nil == filename) || [filename isEqualToString: @""] ) {
|
||||
// it's either not a file part, or
|
||||
// an empty form sent. we won't handle it.
|
||||
return;
|
||||
}
|
||||
|
||||
// 在这里修改文件存储的位置
|
||||
|
||||
NSAssert([self.delegate respondsToSelector:@selector(onSetDestinationPathHttpFileTranSportDestination:)], @"Need to add delegate name onSetDestinationPathHttpFileTranSportDestination to add a destinationPath");
|
||||
|
||||
if ([self.delegate respondsToSelector:@selector(onSetDestinationPathHttpFileTranSportDestination:)]) {
|
||||
self.destinationPath = [self.delegate onSetDestinationPathHttpFileTranSportDestination:self];
|
||||
NSAssert(self.destinationPath.length > 0 || self.destinationPath, @"destinationPath can not be nil");
|
||||
}
|
||||
|
||||
//拼接文件名或者预计文件路径
|
||||
NSString* filePath = [self.destinationPath stringByAppendingPathComponent: filename];
|
||||
self.filePath = filePath;
|
||||
//需要判断是否存在重复文件
|
||||
if ([self.delegate respondsToSelector:@selector(onHttpFileDataEstimateDuplicateCanPassTranSportServer:withPath:andFileName:)]) {
|
||||
if (![self.delegate onHttpFileDataEstimateDuplicateCanPassTranSportServer:self withPath:self.filePath andFileName:filename]) {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
HTTPLogVerbose(@"Saving file to %@", filePath);
|
||||
if(![[NSFileManager defaultManager] createDirectoryAtPath:self.destinationPath withIntermediateDirectories:true attributes:nil error:nil]) {
|
||||
HTTPLogError(@"Could not create directory at path: %@", filePath);
|
||||
}
|
||||
if(![[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil]) {
|
||||
HTTPLogError(@"Could not create file at path: %@", filePath);
|
||||
}
|
||||
storeFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
|
||||
[uploadedFiles addObject: [NSString stringWithFormat:@"/upload/%@", filename]];
|
||||
}
|
||||
|
||||
|
||||
- (void) processContent:(NSData*) data WithHeader:(MultipartMessageHeader*) header {
|
||||
// here we just write the output from parser to the file.
|
||||
if( storeFile ) {
|
||||
[storeFile writeData:data];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) processEndOfPartWithHeader:(MultipartMessageHeader*) header {
|
||||
// as the file part is over, we close the file.
|
||||
[storeFile closeFile];
|
||||
storeFile = nil;
|
||||
}
|
||||
|
||||
- (void) processPreambleData:(NSData*) data {
|
||||
// if we are interested in preamble data, we could process it here.
|
||||
|
||||
}
|
||||
|
||||
- (void) processEpilogueData:(NSData*) data {
|
||||
// if we are interested in epilogue data, we could process it here.
|
||||
//用户更新歌曲数量
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:@"processEpilogueData" object:nil];
|
||||
if ([self.delegate respondsToSelector:@selector(onHttpFileTranSportServer:successWithPath:)]) {
|
||||
[self.delegate onHttpFileTranSportServer:self successWithPath:self.filePath];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user