Files
real-e-party-iOS/YuMi/Tools/CocoaHttpServer/MyHTTPConnection.m
edwinQQQ a35a711be6 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
2025-10-09 16:19:14 +08:00

209 lines
7.7 KiB
Objective-C
Executable File

#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