Files
RestKit/Code/Network/RKParamsAttachment.m
2011-06-20 15:03:35 -04:00

205 lines
5.7 KiB
Objective-C

//
// RKParamsAttachment.m
// RestKit
//
// Created by Blake Watters on 8/6/09.
// Copyright 2009 Two Toasters. All rights reserved.
//
#if TARGET_OS_IPHONE
#import <MobileCoreServices/UTType.h>
#endif
#import "RKParamsAttachment.h"
#import "RKLog.h"
// Set Logging Component
#undef RKLogComponent
#define RKLogComponent lcl_cRestKitNetwork
/**
* The multi-part boundary. See RKParams.m
*/
extern NSString* const kRKStringBoundary;
@interface RKParamsAttachment (Private)
- (NSString *)mimeTypeForExtension:(NSString *)extension;
@end
@implementation RKParamsAttachment
@synthesize fileName = _fileName, MIMEType = _MIMEType, name = _name;
- (id)initWithName:(NSString*)name {
if ((self = [self init])) {
self.name = name;
self.fileName = name;
}
return self;
}
- (id)initWithName:(NSString*)name value:(id<NSObject>)value {
if ((self = [self initWithName:name])) {
NSMutableData* body = [NSMutableData data];
if ([value respondsToSelector:@selector(dataUsingEncoding:)]) {
[body appendData:[(NSString*)value dataUsingEncoding:NSUTF8StringEncoding]];
} else {
[body appendData:[[NSString stringWithFormat:@"%@", value] dataUsingEncoding:NSUTF8StringEncoding]];
}
_bodyStream = [[NSInputStream alloc] initWithData:body];
_bodyLength = [body length];
}
return self;
}
- (id)initWithName:(NSString*)name data:(NSData*)data {
if ((self = [self initWithName:name])) {
_bodyStream = [[NSInputStream alloc] initWithData:data];
_bodyLength = [data length];
}
return self;
}
- (id)initWithName:(NSString*)name file:(NSString*)filePath {
if ((self = [self initWithName:name])) {
NSAssert1([[NSFileManager defaultManager] fileExistsAtPath:filePath], @"Expected file to exist at path: %@", filePath);
_fileName = [[filePath lastPathComponent] retain];
_MIMEType = [[self mimeTypeForExtension:[filePath pathExtension]] retain];
_bodyStream = [[NSInputStream alloc] initWithFileAtPath:filePath];
NSError* error;
NSDictionary* attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error];
if (attributes) {
_bodyLength = [[attributes objectForKey:NSFileSize] unsignedIntegerValue];
}
else {
RKLogError(@"Encountered an error while determining file size: %@", error);
}
}
return self;
}
- (void)dealloc {
[_name release];
[_fileName release];
[_MIMEType release];
[_MIMEHeader release];
_MIMEHeader = nil;
[_bodyStream close];
[_bodyStream release];
_bodyStream = nil;
[super dealloc];
}
- (NSString*)MIMEBoundary {
return kRKStringBoundary;
}
- (NSString *)mimeTypeForExtension:(NSString *)extension {
if (NULL != UTTypeCreatePreferredIdentifierForTag) {
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (CFStringRef)extension, NULL);
if (uti != NULL) {
CFStringRef mime = UTTypeCopyPreferredTagWithClass(uti, kUTTagClassMIMEType);
CFRelease(uti);
if (mime != NULL) {
NSString *type = [NSString stringWithString:(NSString *)mime];
CFRelease(mime);
return type;
}
}
}
return @"application/octet-stream";
}
#pragma mark NSStream methods
- (void)open {
// Generate the MIME header for this part
if (self.fileName && self.MIMEType) {
// Typical for file attachments
_MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"; "
@"filename=\"%@\"\r\nContent-Type: %@\r\n\r\n",
[self MIMEBoundary], self.name, self.fileName, self.MIMEType] dataUsingEncoding:NSUTF8StringEncoding] retain];
} else if (self.MIMEType) {
// Typical for data values
_MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n"
@"Content-Type: %@\r\n\r\n",
[self MIMEBoundary], self.name, self.MIMEType] dataUsingEncoding:NSUTF8StringEncoding] retain];
} else {
// Typical for raw values
_MIMEHeader = [[[NSString stringWithFormat:@"--%@\r\nContent-Disposition: form-data; name=\"%@\"\r\n\r\n",
[self MIMEBoundary], self.name]
dataUsingEncoding:NSUTF8StringEncoding] retain];
}
// Calculate lengths
_MIMEHeaderLength = [_MIMEHeader length];
_length = _MIMEHeaderLength + _bodyLength + 2; // \r\n is the + 2
// Open the stream
[_bodyStream open];
}
- (NSUInteger)length {
return _length;
}
- (NSUInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLength {
NSUInteger sent = 0, read;
// We are done with the read
if (_delivered >= _length) {
return 0;
}
// First we send back the MIME headers
if (_delivered < _MIMEHeaderLength && sent < maxLength) {
NSUInteger headerBytesRemaining, bytesRemainingInBuffer;
headerBytesRemaining = _MIMEHeaderLength - _delivered;
bytesRemainingInBuffer = maxLength;
// Send the entire header if there is room
read = (headerBytesRemaining < bytesRemainingInBuffer) ? headerBytesRemaining : bytesRemainingInBuffer;
[_MIMEHeader getBytes:buffer range:NSMakeRange(_delivered, read)];
sent += read;
_delivered += sent;
}
// Read the attachment body out of our underlying stream
while (_delivered >= _MIMEHeaderLength && _delivered < (_length - 2) && sent < maxLength) {
if ((read = [_bodyStream read:(buffer + sent) maxLength:(maxLength - sent)]) == 0) {
break;
}
sent += read;
_delivered += read;
}
// Append the \r\n
if (_delivered >= (_length - 2) && sent < maxLength) {
if (_delivered == (_length - 2)) {
*(buffer + sent) = '\r';
sent ++;
_delivered ++;
}
*(buffer + sent) = '\n';
sent ++;
_delivered ++;
}
return sent;
}
@end