Commit 93b75196 authored by Felix Paul Kühne's avatar Felix Paul Kühne

Split VLCHTTPConnection and VLCHTTPUploaderController

parent 2ccfa809
//
// VLCHTTPConnection.h
// VLC for iOS
//
// Created by Felix Paul Kühne on 05.11.13.
// Copyright (c) 2013 VideoLAN. All rights reserved.
//
// Refer to the COPYING file of the official project for license.
//
#import "HTTPConnection.h"
@interface VLCHTTPConnection : HTTPConnection
@end
//
// VLCHTTPConnection.m
// VLC for iOS
//
// Created by Felix Paul Kühne on 05.11.13.
// Copyright (c) 2013 VideoLAN. All rights reserved.
//
// Refer to the COPYING file of the official project for license.
//
#import "VLCAppDelegate.h"
#import "VLCHTTPConnection.h"
#import "HTTPConnection.h"
#import "MultipartFormDataParser.h"
#import "HTTPMessage.h"
#import "HTTPDataResponse.h"
#import "HTTPFileResponse.h"
#import "MultipartMessageHeaderField.h"
@interface VLCHTTPConnection()
{
MultipartFormDataParser* _parser;
NSFileHandle* _storeFile;
NSMutableArray* _uploadedFiles;
}
@end
@implementation VLCHTTPConnection
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
{
// Add support for POST
if ([method isEqualToString:@"POST"]) {
if ([path isEqualToString:@"/upload.json"])
return YES;
}
return [super supportsMethod:method atPath:path];
}
- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path
{
// Inform HTTP server that we expect a body to accompany a POST request
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
// 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
{
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
return [[HTTPDataResponse alloc] initWithData:[@"\"OK\"" dataUsingEncoding:NSUTF8StringEncoding]];
}
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
{
// 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
{
/* 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)[@"Content-Disposition"];
NSString* filename = [(disposition.params)[@"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;
}
// create the path where to store the media
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* uploadDirPath = searchPaths[0];
BOOL isDir = YES;
if (![[NSFileManager defaultManager]fileExistsAtPath:uploadDirPath isDirectory:&isDir ]) {
[[NSFileManager defaultManager]createDirectoryAtPath:uploadDirPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString* filePath = [uploadDirPath stringByAppendingPathComponent: filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
_storeFile = nil;
else {
APLog(@"Saving file to %@", filePath);
if (![[NSFileManager defaultManager] createDirectoryAtPath:uploadDirPath withIntermediateDirectories:true attributes:nil error:nil])
APLog(@"Could not create directory at path: %@", filePath);
if (![[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil])
APLog(@"Could not create file at path: %@", filePath);
_storeFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
[_uploadedFiles addObject: [NSString stringWithFormat:@"/upload/%@", filename]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[(VLCAppDelegate*)[UIApplication sharedApplication].delegate disableIdleTimer];
}
}
- (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;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[(VLCAppDelegate*)[UIApplication sharedApplication].delegate activateIdleTimer];
/* update media library when file upload was completed */
VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate updateMediaList];
}
@end
......@@ -8,17 +8,11 @@
// Refer to the COPYING file of the official project for license.
//
#import "VLCHTTPUploaderController.h"
#import "VLCAppDelegate.h"
#import "VLCHTTPUploaderController.h"
#import "VLCHTTPConnection.h"
#import "HTTPServer.h"
#import "HTTPConnection.h"
#import "HTTPMessage.h"
#import "HTTPDataResponse.h"
#import "HTTPFileResponse.h"
#import "MultipartFormDataParser.h"
#import "MultipartMessageHeaderField.h"
#import <ifaddrs.h>
#import <arpa/inet.h>
......@@ -29,14 +23,6 @@
NSString *const WifiInterfaceName = @"en0";
#endif
@interface VLCHTTPConnection : HTTPConnection {
MultipartFormDataParser* _parser;
NSFileHandle* _storeFile;
NSMutableArray* _uploadedFiles;
}
@end
@implementation VLCHTTPUploaderController
- (id)init
......@@ -136,161 +122,3 @@
}
@end
/**
* All we have to do is override appropriate methods in HTTPConnection.
**/
@implementation VLCHTTPConnection
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
{
// Add support for POST
if ([method isEqualToString:@"POST"]) {
if ([path isEqualToString:@"/upload.json"])
return YES;
}
return [super supportsMethod:method atPath:path];
}
- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path
{
// Inform HTTP server that we expect a body to accompany a POST request
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
// 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
{
if ([method isEqualToString:@"POST"] && [path isEqualToString:@"/upload.json"]) {
return [[HTTPDataResponse alloc] initWithData:[@"\"OK\"" dataUsingEncoding:NSUTF8StringEncoding]];
}
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
{
// 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
{
/* 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)[@"Content-Disposition"];
NSString* filename = [(disposition.params)[@"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;
}
// create the path where to store the media
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString* uploadDirPath = searchPaths[0];
BOOL isDir = YES;
if (![[NSFileManager defaultManager]fileExistsAtPath:uploadDirPath isDirectory:&isDir ]) {
[[NSFileManager defaultManager]createDirectoryAtPath:uploadDirPath withIntermediateDirectories:YES attributes:nil error:nil];
}
NSString* filePath = [uploadDirPath stringByAppendingPathComponent: filename];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath])
_storeFile = nil;
else {
APLog(@"Saving file to %@", filePath);
if (![[NSFileManager defaultManager] createDirectoryAtPath:uploadDirPath withIntermediateDirectories:true attributes:nil error:nil])
APLog(@"Could not create directory at path: %@", filePath);
if (![[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil])
APLog(@"Could not create file at path: %@", filePath);
_storeFile = [NSFileHandle fileHandleForWritingAtPath:filePath];
[_uploadedFiles addObject: [NSString stringWithFormat:@"/upload/%@", filename]];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[(VLCAppDelegate*)[UIApplication sharedApplication].delegate disableIdleTimer];
}
}
- (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;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[(VLCAppDelegate*)[UIApplication sharedApplication].delegate activateIdleTimer];
/* update media library when file upload was completed */
VLCAppDelegate* appDelegate = [UIApplication sharedApplication].delegate;
[appDelegate updateMediaList];
}
@end
......@@ -206,6 +206,7 @@
7D94FCF816DE7D1100F2623B /* VLCPlaylistViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D94FCF716DE7D1100F2623B /* VLCPlaylistViewController.m */; };
7D94FCFB16DE7D1100F2623B /* VLCMovieViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D94FCFA16DE7D1100F2623B /* VLCMovieViewController.m */; };
7D9529531732EFCA006F5B40 /* VLCAboutViewController~ipad.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7D9529521732EFCA006F5B40 /* VLCAboutViewController~ipad.xib */; };
7D9B6847182864CC00798BFF /* VLCHTTPConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D9B6846182864CC00798BFF /* VLCHTTPConnection.m */; };
7D9F7FB117F969B0000A6500 /* VLCSidebarViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7D9F7FB017F969B0000A6500 /* VLCSidebarViewCell.m */; };
7DA6209B170A0CE500643D11 /* VLCPlaylistTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 7DA6209A170A0CE500643D11 /* VLCPlaylistTableViewCell.m */; };
7DA8B0FB173318E80029698C /* SourceCodePro-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 7DA8B0F9173318E80029698C /* SourceCodePro-Regular.ttf */; };
......@@ -653,6 +654,8 @@
7D94FCF916DE7D1100F2623B /* VLCMovieViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = VLCMovieViewController.h; sourceTree = "<group>"; };
7D94FCFA16DE7D1100F2623B /* VLCMovieViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VLCMovieViewController.m; sourceTree = "<group>"; };
7D9529521732EFCA006F5B40 /* VLCAboutViewController~ipad.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = "VLCAboutViewController~ipad.xib"; path = "Resources/VLCAboutViewController~ipad.xib"; sourceTree = SOURCE_ROOT; };
7D9B6845182864CC00798BFF /* VLCHTTPConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VLCHTTPConnection.h; sourceTree = "<group>"; };
7D9B6846182864CC00798BFF /* VLCHTTPConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = VLCHTTPConnection.m; sourceTree = "<group>"; };
7D9B6B0817C9625F00F9425D /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/Localizable.strings; sourceTree = "<group>"; };
7D9B6B0917C9625F00F9425D /* sl */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = sl; path = "sl.lproj/badgeUnread@2x~ipad.png"; sourceTree = "<group>"; };
7D9B6B0A17C9626000F9425D /* sl */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = sl; path = "sl.lproj/badgeUnread@2x~iphone.png"; sourceTree = "<group>"; };
......@@ -1335,6 +1338,8 @@
7D5F7ABA175265CB006CCCFA /* HTTP Connectivity */ = {
isa = PBXGroup;
children = (
7D9B6845182864CC00798BFF /* VLCHTTPConnection.h */,
7D9B6846182864CC00798BFF /* VLCHTTPConnection.m */,
29CE2D41174912C600922D8F /* VLCHTTPUploaderController.h */,
29CE2D42174912C600922D8F /* VLCHTTPUploaderController.m */,
7D3EB015174A46FB002062C2 /* VLCHTTPFileDownloader.h */,
......@@ -2157,6 +2162,7 @@
7D93045917B6ACA10054EAC6 /* VLCWiFiUploadTableViewCell.m in Sources */,
7D02B0D217B6BE850099030D /* VLCLocalServerFolderListViewController.m in Sources */,
7DC72D6317B7ED24008A26D0 /* WhiteRaccoon.m in Sources */,
7D9B6847182864CC00798BFF /* VLCHTTPConnection.m in Sources */,
7DC72D6917B820C9008A26D0 /* VLCNetworkLoginViewController.m in Sources */,
A7B5315F17E35B6E00EAE4B3 /* VLCThumbnailsCache.m in Sources */,
7D9F7FB117F969B0000A6500 /* VLCSidebarViewCell.m in Sources */,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment