Resume download (download files with range)
Cancel active content transmissions
Support for Secondary Object Type Ids
Read support for ACLs (ACL Parser)
Fix for files with double byte characters in their filename (error body stream exhausted while uploading)
Fix for delete tree method (e.g. For Microsoft Sharepoint)

git-svn-id: https://svn.apache.org/repos/asf/chemistry/objectivecmis/trunk@1578378 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.h b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.h
index 5f7364d..dec77dc 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.h
+++ b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.h
@@ -26,10 +26,11 @@
 #import "CMISAllowableActionsParser.h"
 #import "CMISAtomPubExtensionElementParser.h"
 #import "CMISAtomPubExtensionDataParserBase.h"
+#import "CMISAclParser.h"
 
 @protocol CMISAtomEntryParserDelegate;
 
-@interface CMISAtomEntryParser : CMISAtomPubExtensionDataParserBase <NSXMLParserDelegate, CMISAllowableActionsParserDelegate>
+@interface CMISAtomEntryParser : CMISAtomPubExtensionDataParserBase <NSXMLParserDelegate, CMISAllowableActionsParserDelegate, CMISAclParserDelegate>
 
 @property (nonatomic, strong, readonly) CMISObjectData *objectData;
 
diff --git a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.m b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.m
index 7d772be..0831b7d 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryParser.m
@@ -35,6 +35,7 @@
 @property (nonatomic, strong) CMISRenditionData *currentRendition;
 @property (nonatomic, strong) NSMutableArray *currentRenditions;
 @property (nonatomic, strong) NSMutableString *string;
+@property (nonatomic, assign) BOOL isExcatAcl;
 @property (nonatomic, assign) BOOL parsingRelationship;
 
 @property (nonatomic, weak) id<NSXMLParserDelegate, CMISAtomEntryParserDelegate> parentDelegate;
@@ -150,6 +151,9 @@
         } else if ([elementName isEqualToString:kCMISAtomEntryAllowableActions]) {
             // Delegate parsing to child parser for allowableActions element
             self.childParserDelegate = [CMISAllowableActionsParser allowableActionsParserWithParentDelegate:self parser:parser];
+        } else if ([elementName isEqualToString:kCMISAtomEntryAcl]) {
+            // Delegate parsing to child parser for acl element
+            self.childParserDelegate = [CMISAclParser aclParserWithParentDelegate:self parser:parser];
         } else if ([elementName isEqualToString:kCMISCoreRelationship]) {
             // NOTE: we're currently ignoring the relationship element so set a flag to check
             self.parsingRelationship = YES;
@@ -239,7 +243,12 @@
                 }
                 [self.currentRenditions addObject:self.currentRendition];
                 self.currentRendition = nil;
-            }
+        	} else if ([elementName isEqualToString:kCMISAtomEntryExactACL]) {
+            	self.isExcatAcl = [self.string isEqualToString:@"true"] ? YES : NO;
+            	if(self.objectData.acl){
+                	[self.objectData.acl setIsExact:self.isExcatAcl];
+            	}
+			}
         }
         
         // the relationship element has ended
@@ -305,4 +314,10 @@
     self.objectData.allowableActions = allowableActions;
 }
 
+#pragma mark - CMISAclParserDelegate Methods
+-(void)aclParser:(CMISAclParser *)aclParser didFinishParsingAcl:(CMISAcl *)acl{
+    self.objectData.acl = acl;
+    [self.objectData.acl setIsExact:self.isExcatAcl];
+}
+
 @end
diff --git a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryWriter.m b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryWriter.m
index c14ab84..4c1cab8 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryWriter.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomEntryWriter.m
@@ -200,7 +200,7 @@
             }
             default:
             {
-                CMISLogDebug(@"Property type did not match: %u", propertyData.type);
+                CMISLogDebug(@"Property type did not match: %d", propertyData.type);
                 break;
             }
         }
diff --git a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.h b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.h
index e5a3ccf..d593713 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.h
+++ b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.h
@@ -47,6 +47,12 @@
 extern NSString * const kCMISAtomEntryContent;
 extern NSString * const kCMISAtomEntrySrc;
 extern NSString * const kCMISAtomEntryAllowableActions;
+extern NSString * const kCMISAtomEntryAcl;
+extern NSString * const kCMISAtomEntryExactACL;
+extern NSString * const kCMISAtomEntryPermission;
+extern NSString * const kCMISAtomEntryPrincipal;
+extern NSString * const kCMISAtomEntryPrincipalId;
+extern NSString * const kCMISAtomEntryDirect;
 
 // Collections
 extern NSString * const kCMISAtomCollectionQuery;
diff --git a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.m b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.m
index 978d2aa..9637f8e 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/AtomPubParser/CMISAtomPubConstants.m
@@ -47,6 +47,12 @@
 NSString * const kCMISAtomEntryContent = @"content";
 NSString * const kCMISAtomEntrySrc = @"src";
 NSString * const kCMISAtomEntryAllowableActions = @"allowableActions";
+NSString * const kCMISAtomEntryAcl = @"acl";
+NSString * const kCMISAtomEntryExactACL = @"exactACL";
+NSString * const kCMISAtomEntryPermission = @"permission";
+NSString * const kCMISAtomEntryPrincipal = @"principal";
+NSString * const kCMISAtomEntryPrincipalId = @"principalId";
+NSString * const kCMISAtomEntryDirect = @"direct";
 
 // Collections
 NSString * const kCMISAtomCollectionQuery = @"query";
diff --git a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService+Protected.h b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService+Protected.h
index 39c5a81..04b1e9d 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService+Protected.h
+++ b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService+Protected.h
@@ -113,6 +113,6 @@
                  bytesExpected:(unsigned long long)bytesExpected
                    cmisRequest:(CMISRequest*)request
                completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-                 progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                 progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
diff --git a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService.m b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService.m
index c0b6909..5a94505 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubBaseService.m
@@ -379,7 +379,7 @@
                                             }
                                         }
                                     } else {
-                                        CMISLogError(@"Invalid http response status code when sending atom entry: %d", response.statusCode);
+                                        CMISLogError(@"Invalid http response status code when sending atom entry: %ld", (long)response.statusCode);
                                         CMISLogError(@"Error content: %@", [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]);
                                         if (completionBlock) {
                                             completionBlock(nil, [CMISErrors createCMISErrorWithCode:kCMISErrorCodeRuntime
@@ -397,7 +397,7 @@
                  bytesExpected:(unsigned long long)bytesExpected
                    cmisRequest:(CMISRequest*)request
                completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-                 progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                 progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     // Validate param
     if (link == nil) {
@@ -438,7 +438,7 @@
                                             }
                                         }
                                     } else {
-                                        CMISLogError(@"Invalid http response status code when sending atom entry: %d", response.statusCode);
+                                        CMISLogError(@"Invalid http response status code when sending atom entry: %d", (int)response.statusCode);
                                         CMISLogError(@"Error content: %@", [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]);
                                         if (completionBlock) {
                                             completionBlock(nil, [CMISErrors createCMISErrorWithCode:kCMISErrorCodeRuntime
diff --git a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubObjectService.m b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubObjectService.m
index b9d3621..34778b9 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubObjectService.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubObjectService.m
@@ -87,10 +87,31 @@
                         completionBlock:(void (^)(NSError *error))completionBlock
                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    return [self downloadContentOfObject:objectId
+                         streamId:streamId
+                           toFile:filePath
+                           offset:nil
+                           length:nil
+                  completionBlock:completionBlock
+                    progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                        progressBlock(bytesDownloaded, bytesTotal);
+                    }];
+}
+
+- (CMISRequest*)downloadContentOfObject:(NSString *)objectId
+                               streamId:(NSString *)streamId
+                                 toFile:(NSString *)filePath
+                                 offset:(NSDecimalNumber*)offset
+                                 length:(NSDecimalNumber*)length
+                        completionBlock:(void (^)(NSError *error))completionBlock
+                          progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
     NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
     return [self downloadContentOfObject:objectId
                                 streamId:streamId
                           toOutputStream:outputStream
+                                  offset:offset
+                                  length:length
                          completionBlock:completionBlock
                            progressBlock:progressBlock];
 }
@@ -101,6 +122,25 @@
                         completionBlock:(void (^)(NSError *error))completionBlock
                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    return [self downloadContentOfObject:objectId
+                                streamId:streamId
+                          toOutputStream:outputStream
+                                  offset:nil
+                                  length:nil
+                         completionBlock:completionBlock
+                           progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                               progressBlock(bytesDownloaded, bytesTotal);
+                           }];
+}
+
+- (CMISRequest*)downloadContentOfObject:(NSString *)objectId
+                               streamId:(NSString *)streamId
+                         toOutputStream:(NSOutputStream *)outputStream
+                                 offset:(NSDecimalNumber*)offset
+                                 length:(NSDecimalNumber*)length
+                        completionBlock:(void (^)(NSError *error))completionBlock
+                          progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
     CMISRequest *request = [[CMISRequest alloc] init];
     
     [self retrieveObjectInternal:objectId
@@ -127,6 +167,8 @@
                                                     session:self.bindingSession
                                                outputStream:outputStream
                                               bytesExpected:streamLength
+                                                     offset:offset
+                                                     length:length
                                                 cmisRequest:request
                                             completionBlock:^(CMISHttpResponse *httpResponse, NSError *error)
                  {
@@ -198,7 +240,7 @@
                     overwriteExisting:(BOOL)overwrite
                           changeToken:(CMISStringInOutParameter *)changeTokenParam
                       completionBlock:(void (^)(NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:filePath];
     if (inputStream == nil) {
@@ -234,7 +276,7 @@
                     overwriteExisting:(BOOL)overwrite
                           changeToken:(CMISStringInOutParameter *)changeTokenParam
                       completionBlock:(void (^)(NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     CMISRequest *request = [[CMISRequest alloc] init];
     // Validate object id param
@@ -307,7 +349,7 @@
                  if (httpResponse.statusCode == 200 || httpResponse.statusCode == 201 || httpResponse.statusCode == 204) {
                      error = nil;
                  } else {
-                     CMISLogError(@"Invalid http response status code when updating content: %d", httpResponse.statusCode);
+                     CMISLogError(@"Invalid http response status code when updating content: %d", (int)httpResponse.statusCode);
                      error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeRuntime
                                              detailedDescription:[NSString stringWithFormat:@"Could not update content: http status code %li", (long)httpResponse.statusCode]];
                  }
@@ -328,7 +370,7 @@
                                 properties:(CMISProperties *)properties
                                   inFolder:(NSString *)folderObjectId
                            completionBlock:(void (^)(NSString *objectId, NSError *Error))completionBlock
-                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:filePath];
     if (inputStream == nil) {
@@ -361,7 +403,7 @@
                                      inFolder:(NSString *)folderObjectId
                                 bytesExpected:(unsigned long long)bytesExpected // optional
                               completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     // Validate properties
     if ([properties propertyValueForId:kCMISPropertyName] == nil || [properties propertyValueForId:kCMISPropertyObjectTypeId] == nil) {
@@ -492,52 +534,88 @@
     }
     CMISRequest *request = [[CMISRequest alloc] init];
     
+    // find the down links
     [self loadLinkForObjectId:folderObjectId
                      relation:kCMISLinkRelationDown
-                         type:kCMISMediaTypeDescendants
+                         type:nil
                   cmisRequest:request
               completionBlock:^(NSString *link, NSError *error) {
-        if (error) {
-            CMISLogError(@"Error while fetching %@ link : %@", kCMISLinkRelationDown, error.description);
-            completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
-            return;
-        }
-        
-        void (^continueWithLink)(NSString *) = ^(NSString *link) {
+
+        __block NSString *childrenLink = nil;
+
+        void (^continueWithLink)(NSString*) = ^(NSString* link) {
+            if(!link){
+                link = childrenLink;
+            }
+            
+            if(!link){
+                CMISLogError(@"Could not retrieve %@ nor %@ link", kCMISLinkRelationDown, kCMISLinkRelationFolderTree);
+                completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
+                return;
+            }
+            
             link = [CMISURLUtil urlStringByAppendingParameter:kCMISParameterAllVersions value:(allVersions ? @"true" : @"false") urlString:link];
             link = [CMISURLUtil urlStringByAppendingParameter:kCMISParameterUnfileObjects value:[CMISEnums stringForUnfileObject:unfileObjects] urlString:link];
             link = [CMISURLUtil urlStringByAppendingParameter:kCMISParameterContinueOnFailure value:(continueOnFailure ? @"true" : @"false") urlString:link];
-            
+
             [self.bindingSession.networkProvider invokeDELETE:[NSURL URLWithString:link]
-                                                      session:self.bindingSession
-                                                  cmisRequest:request
-                                              completionBlock:^(CMISHttpResponse *httpResponse, NSError *error) {
-                       if (httpResponse) {
-                           // TODO: retrieve failed folders and files and return
-                           completionBlock([NSArray array], nil);
-                       } else {
-                           completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeConnection]);
-                       }
-                   }];
+                                                    session:self.bindingSession
+                                                cmisRequest:request
+                                            completionBlock:^(CMISHttpResponse *httpResponse, NSError *error) {
+                                                if (httpResponse) {
+                                                    // TODO: retrieve failed folders and files and return
+                                                    completionBlock([NSArray array], nil);
+                                                } else {
+                                                    completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeConnection]);
+                                                }
+                                            }];
         };
-        
-        if (link == nil) {
-            [self loadLinkForObjectId:folderObjectId
-                             relation:kCMISLinkRelationFolderTree
-                          cmisRequest:request
-                      completionBlock:^(NSString *link, NSError *error) {
-                if (error) {
-                    CMISLogError(@"Error while fetching %@ link : %@", kCMISLinkRelationFolderTree, error.description);
-                    completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
-                } else if (link == nil) {
-                    CMISLogError(@"Could not retrieve %@ nor %@ link", kCMISLinkRelationDown, kCMISLinkRelationFolderTree);
-                    completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
-                } else {
-                    continueWithLink(link);
-                }
-            }];
+                  
+        void (^continueWithLinkFolderTreeFeed)(NSString*) = ^(NSString* link) {
+            if(!link){
+                [self loadLinkForObjectId:folderObjectId
+                                 relation:kCMISLinkRelationFolderTree
+                                     type:kCMISMediaTypeFeed
+                              cmisRequest:request
+                          completionBlock:^(NSString *link, NSError *error) {
+                              continueWithLink(link);
+                          }];
+            } else {
+                continueWithLink(link);   
+            }
+        };
+                  
+        void (^continueWithLinksFolderTreeDescendants)(NSString*) = ^(NSString* link) {
+            if(!link) {
+                [self loadLinkForObjectId:folderObjectId
+                                 relation:kCMISLinkRelationFolderTree
+                                     type:kCMISMediaTypeDescendants
+                              cmisRequest:request
+                          completionBlock:^(NSString *link, NSError *error) {
+                              continueWithLinkFolderTreeFeed(link);
+                          }];
+            } else {
+                continueWithLinkFolderTreeFeed(link);
+            }
+        };
+                  
+
+        if(link){
+            // found only a children link, but no descendants link
+            // -> try folder tree link
+            childrenLink = link;
+            link = nil;
+            continueWithLinksFolderTreeDescendants(link);
         } else {
-            continueWithLink(link);
+            // found no or two down links
+            // -> get only the descendants link
+            [self loadLinkForObjectId:folderObjectId
+                           relation:kCMISLinkRelationDown
+                               type:kCMISMediaTypeDescendants
+                        cmisRequest:request
+                    completionBlock:^(NSString *link, NSError *error) {
+                        continueWithLinksFolderTreeDescendants(link);
+                    }];
         }
     }];
     return request;
diff --git a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubVersioningService.m b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubVersioningService.m
index 2af2fb0..58a29a2 100644
--- a/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubVersioningService.m
+++ b/ObjectiveCMIS/Bindings/AtomPub/CMISAtomPubVersioningService.m
@@ -182,7 +182,7 @@
              properties:(CMISProperties *)properties
          checkinComment:(NSString *)checkinComment
         completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:filePath];
     if (inputStream == nil) {
@@ -218,7 +218,7 @@
              properties:(CMISProperties *)properties
          checkinComment:(NSString *)checkinComment
         completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     // Validate params
     if (!objectId) {
diff --git a/ObjectiveCMIS/Bindings/CMISObjectService.h b/ObjectiveCMIS/Bindings/CMISObjectService.h
index 3a88227..5ed2434 100644
--- a/ObjectiveCMIS/Bindings/CMISObjectService.h
+++ b/ObjectiveCMIS/Bindings/CMISObjectService.h
@@ -65,6 +65,20 @@
 
 /**
  * Gets the content stream for the specified Document object, or gets a rendition stream for a specified
+ * rendition of a document or folder object. Downloads the content to a local file.
+ * completionBlock returns objectData for object or nil if unsuccessful
+ * Provides options to resume and cancel download
+ */
+- (CMISRequest*)downloadContentOfObject:(NSString *)objectId
+                               streamId:(NSString *)streamId
+                                 toFile:(NSString *)filePath
+                                 offset:(NSDecimalNumber*)offset
+                                 length:(NSDecimalNumber*)length
+                        completionBlock:(void (^)(NSError *error))completionBlock
+                          progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+/**
+ * Gets the content stream for the specified Document object, or gets a rendition stream for a specified
  * rendition of a document or folder object. Downloads the content to an output stream.
  * completionBlock returns objectData for object or nil if unsuccessful
  */
@@ -75,6 +89,21 @@
                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
 
 /**
+ * Gets the content stream for the specified Document object, or gets a rendition stream for a specified
+ * rendition of a document or folder object. Downloads the content to an output stream.
+ * completionBlock returns objectData for object or nil if unsuccessful
+ * Provides options to resume and cancel download
+ */
+- (CMISRequest*)downloadContentOfObject:(NSString *)objectId
+                               streamId:(NSString *)streamId
+                         toOutputStream:(NSOutputStream *)outputStream
+                                 offset:(NSDecimalNumber*)offset
+                                 length:(NSDecimalNumber*)length
+                        completionBlock:(void (^)(NSError *error))completionBlock
+                          progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+
+/**
  * Deletes the content stream for the specified document object.
  *
  * A Repository MAY automatically create new Document versions as part of this service method.
@@ -106,7 +135,7 @@
                     overwriteExisting:(BOOL)overwrite
                           changeToken:(CMISStringInOutParameter *)changeTokenParam
                       completionBlock:(void (^)(NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Changes the content of the given document to the content from a give input stream.
@@ -128,7 +157,7 @@
                     overwriteExisting:(BOOL)overwrite
                           changeToken:(CMISStringInOutParameter *)changeToken
                       completionBlock:(void (^)(NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * uploads the file from the given path to the given folder.
@@ -140,7 +169,7 @@
                                 properties:(CMISProperties *)properties
                                   inFolder:(NSString *)folderObjectId
                            completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * uploads the file from the given input stream to the given folder.
@@ -153,7 +182,7 @@
                                      inFolder:(NSString *)folderObjectId
                                 bytesExpected:(unsigned long long)bytesExpected // optional
                               completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Deletes the given object.
diff --git a/ObjectiveCMIS/Bindings/CMISVersioningService.h b/ObjectiveCMIS/Bindings/CMISVersioningService.h
index eea5e9e..629a7c3 100644
--- a/ObjectiveCMIS/Bindings/CMISVersioningService.h
+++ b/ObjectiveCMIS/Bindings/CMISVersioningService.h
@@ -99,7 +99,7 @@
              properties:(CMISProperties *)properties
          checkinComment:(NSString *)checkinComment
         completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Checks-in the private working copy (PWC) document from the given an input stream.
@@ -122,6 +122,6 @@
              properties:(CMISProperties *)properties
          checkinComment:(NSString *)checkinComment
         completionBlock:(void (^)(CMISObjectData *objectData, NSError *error))completionBlock
-          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+          progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
diff --git a/ObjectiveCMIS/Client/CMISDocument.h b/ObjectiveCMIS/Client/CMISDocument.h
index fb472d2..66be650 100644
--- a/ObjectiveCMIS/Client/CMISDocument.h
+++ b/ObjectiveCMIS/Client/CMISDocument.h
@@ -79,6 +79,29 @@
                                 progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
 
 /**
+ * Downloads the content to a local file and returns the filepath.
+ * completionBlock will return NSError nil if successful
+ * Provides options to resume and cancel download
+ */
+- (CMISRequest*)downloadContentToFile:(NSString *)filePath
+                               offset:(NSDecimalNumber*)offset
+                               length:(NSDecimalNumber*)length
+                      completionBlock:(void (^)(NSError *error))completionBlock
+                        progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+
+/**
+ * Downloads the content to an outputstream and returns the handle to the http request in order to allow cancellation.
+ * completionBlock will return NSError nil if successful
+ * Provides options to resume and cancel download
+ */
+- (CMISRequest*)downloadContentToOutputStream:(NSOutputStream *)outputStream
+                                       offset:(NSDecimalNumber*)offset
+                                       length:(NSDecimalNumber*)length
+                              completionBlock:(void (^)(NSError *error))completionBlock
+                                progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+/**
  * Changes the content of this document to the content of the given file.
  *
  * Optional overwrite flag: If TRUE (default), then the Repository MUST replace the existing content stream for the
@@ -90,7 +113,7 @@
                                     mimeType:(NSString *)mimeType
                                    overwrite:(BOOL)overwrite
                              completionBlock:(void (^)(NSError *error))completionBlock
-                               progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                               progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Changes the content of this document to the content of the given input stream.
@@ -106,7 +129,7 @@
                                            mimeType:(NSString *)mimeType
                                           overwrite:(BOOL)overwrite
                                     completionBlock:(void (^)(NSError *error))completionBlock
-                                      progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                                      progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Deletes the content of this document.
@@ -139,7 +162,7 @@
                            properties:(CMISProperties *)properties
                        checkinComment:(NSString *)checkinComment
                       completionBlock:(void (^)(CMISDocument *document, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Checkin this PWC from a specified input stream and return the checked-in document
@@ -151,6 +174,6 @@
                            properties:(CMISProperties *)properties
                        checkinComment:(NSString *)checkinComment
                       completionBlock:(void (^)(CMISDocument *document, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
diff --git a/ObjectiveCMIS/Client/CMISDocument.m b/ObjectiveCMIS/Client/CMISDocument.m
index ac48dea..85a9526 100644
--- a/ObjectiveCMIS/Client/CMISDocument.m
+++ b/ObjectiveCMIS/Client/CMISDocument.m
@@ -87,7 +87,7 @@
                                     mimeType:(NSString *)mimeType
                                    overwrite:(BOOL)overwrite
                              completionBlock:(void (^)(NSError *error))completionBlock
-                               progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                               progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     return [self.binding.objectService changeContentOfObject:[CMISStringInOutParameter inOutParameterUsingInParameter:self.identifier]
                                              toContentOfFile:filePath
@@ -104,7 +104,7 @@
                                            mimeType:(NSString *)mimeType
                                           overwrite:(BOOL)overwrite
                                     completionBlock:(void (^)(NSError *error))completionBlock
-                                      progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                                      progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     return [self.binding.objectService changeContentOfObject:[CMISStringInOutParameter inOutParameterUsingInParameter:self.identifier]
                                       toContentOfInputStream:inputStream
@@ -156,12 +156,13 @@
                       completionBlock:(void (^)(NSError *error))completionBlock
                         progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
-    NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
-    return [self.binding.objectService downloadContentOfObject:self.identifier
-                                                      streamId:nil
-                                                toOutputStream:outputStream
-                                               completionBlock:completionBlock
-                                                 progressBlock:progressBlock];
+    return [self downloadContentToFile:filePath
+                                offset:nil
+                                length:nil
+                       completionBlock:completionBlock
+                         progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                             progressBlock(bytesDownloaded, bytesTotal);
+                         }];
 }
 
 
@@ -169,9 +170,43 @@
                               completionBlock:(void (^)(NSError *error))completionBlock
                                 progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    return [self downloadContentToOutputStream:outputStream
+                                        offset:nil
+                                        length:nil
+                               completionBlock:completionBlock
+                                 progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                                     progressBlock(bytesDownloaded, bytesTotal);
+                                 }];
+}
+
+- (CMISRequest*)downloadContentToFile:(NSString *)filePath
+                               offset:(NSDecimalNumber*)offset
+                               length:(NSDecimalNumber*)length
+                      completionBlock:(void (^)(NSError *error))completionBlock
+                        progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
+    NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
     return [self.binding.objectService downloadContentOfObject:self.identifier
                                                       streamId:nil
                                                 toOutputStream:outputStream
+                                                        offset:offset
+                                                        length:length
+                                               completionBlock:completionBlock
+                                                 progressBlock:progressBlock];
+}
+
+
+- (CMISRequest*)downloadContentToOutputStream:(NSOutputStream *)outputStream
+                                       offset:(NSDecimalNumber*)offset
+                                       length:(NSDecimalNumber*)length
+                              completionBlock:(void (^)(NSError *error))completionBlock
+                                progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
+    return [self.binding.objectService downloadContentOfObject:self.identifier
+                                                      streamId:nil
+                                                toOutputStream:outputStream
+                                                        offset:offset
+                                                        length:length
                                                completionBlock:completionBlock
                                                  progressBlock:progressBlock];
 }
@@ -216,7 +251,7 @@
                            properties:(CMISProperties *)properties
                        checkinComment:(NSString *)checkinComment
                       completionBlock:(void (^)(CMISDocument *document, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     return [self.binding.versioningService checkIn:self.identifier
                                     asMajorVersion:majorVersion
@@ -237,8 +272,8 @@
                 }
             }];
         }
-    } progressBlock:^(unsigned long long bytesUploaded, unsigned long long bytesTotal) {
-        progressBlock(bytesUploaded, bytesTotal);
+    } progressBlock:^(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop) {
+        progressBlock(bytesUploaded, bytesTotal, stop);
     }];
 }
 
@@ -249,7 +284,7 @@
                            properties:(CMISProperties *)properties
                        checkinComment:(NSString *)checkinComment
                       completionBlock:(void (^)(CMISDocument *document, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     return [self.binding.versioningService checkIn:self.identifier
                                     asMajorVersion:majorVersion
@@ -271,8 +306,8 @@
                 }
             }];
         }
-    } progressBlock:^(unsigned long long bytesUploaded, unsigned long long bytesTotal) {
-        progressBlock(bytesUploaded, bytesTotal);
+    } progressBlock:^(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop) {
+        progressBlock(bytesUploaded, bytesTotal, stop);
     }];
 }
 
diff --git a/ObjectiveCMIS/Client/CMISFolder.h b/ObjectiveCMIS/Client/CMISFolder.h
index 98ca604..5930a80 100644
--- a/ObjectiveCMIS/Client/CMISFolder.h
+++ b/ObjectiveCMIS/Client/CMISFolder.h
@@ -68,7 +68,7 @@
                           mimeType:(NSString *)mimeType
                         properties:(NSDictionary *)properties
                    completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * creates a document with specified properties, mime Type
@@ -79,7 +79,7 @@
                            properties:(NSDictionary *)properties
                         bytesExpected:(unsigned long long)bytesExpected
                       completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 
 /**
diff --git a/ObjectiveCMIS/Client/CMISFolder.m b/ObjectiveCMIS/Client/CMISFolder.m
index 6fdaed8..853c379 100644
--- a/ObjectiveCMIS/Client/CMISFolder.m
+++ b/ObjectiveCMIS/Client/CMISFolder.m
@@ -141,7 +141,7 @@
                                   mimeType:(NSString *)mimeType
                                 properties:(NSDictionary *)properties
                            completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                             progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     __block CMISRequest *request = [[CMISRequest alloc] init];
     [self.session.objectConverter convertProperties:properties
@@ -169,7 +169,7 @@
                                    properties:(NSDictionary *)properties
                                 bytesExpected:(unsigned long long)bytesExpected
                               completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                                progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     __block CMISRequest *request = [[CMISRequest alloc] init];
     [self.session.objectConverter convertProperties:properties forObjectTypeId:kCMISPropertyObjectTypeIdValueDocument completionBlock:^(CMISProperties *convertedProperties, NSError *error){
diff --git a/ObjectiveCMIS/Client/CMISObject.h b/ObjectiveCMIS/Client/CMISObject.h
index 73ce66c..d06536c 100644
--- a/ObjectiveCMIS/Client/CMISObject.h
+++ b/ObjectiveCMIS/Client/CMISObject.h
@@ -40,6 +40,7 @@
 //@property (nonatomic, strong, readonly) CMISBaseTypeId *baseTypeId;
 //@property (nonatomic, strong, readonly) CMISObjectType *baseType;
 //@property (nonatomic, strong, readonly) CMISObjectType *type;
+@property (nonatomic, strong, readonly) CMISAcl *acl;
 @property (nonatomic, strong, readonly) CMISAllowableActions *allowableActions;
 @property (nonatomic, strong, readonly) NSArray *renditions; // An array containing CMISRendition objects
 
diff --git a/ObjectiveCMIS/Client/CMISObject.m b/ObjectiveCMIS/Client/CMISObject.m
index 5fed464..3521d03 100644
--- a/ObjectiveCMIS/Client/CMISObject.m
+++ b/ObjectiveCMIS/Client/CMISObject.m
@@ -33,7 +33,6 @@
 @property (nonatomic, strong, readwrite) CMISSession *session;
 @property (nonatomic, strong, readwrite) id<CMISBinding> binding;
 
-@property (nonatomic, strong, readwrite) NSString *identifier;
 @property (nonatomic, strong, readwrite) NSString *name;
 @property (nonatomic, strong, readwrite) NSString *createdBy;
 @property (nonatomic, strong, readwrite) NSDate *creationDate;
@@ -45,6 +44,7 @@
 
 @property (nonatomic, strong, readwrite) CMISProperties *properties;
 @property (nonatomic, strong, readwrite) CMISAllowableActions *allowableActions;
+@property (nonatomic, strong, readwrite) CMISAcl *acl;
 @property (nonatomic, strong, readwrite) NSArray *renditions;
 
 @property (nonatomic, strong) NSMutableDictionary *extensionsDict;
@@ -72,12 +72,14 @@
         self.changeToken = [[self.properties propertyForId:kCMISPropertyChangeToken] firstValue];
 
         self.allowableActions = objectData.allowableActions;
+        self.acl = objectData.acl;
 
         // Extract Extensions and store in the extensionsDict
         self.extensionsDict = [[NSMutableDictionary alloc] init];
         [self.extensionsDict setObject:[self nonNilArray:objectData.extensions] forKey:[NSNumber numberWithInteger:CMISExtensionLevelObject]];
         [self.extensionsDict setObject:[self nonNilArray:self.properties.extensions] forKey:[NSNumber numberWithInteger:CMISExtensionLevelProperties]];
         [self.extensionsDict setObject:[self nonNilArray:self.allowableActions.extensions] forKey:[NSNumber numberWithInteger:CMISExtensionLevelAllowableActions]];
+        [self.extensionsDict setObject:[self nonNilArray:self.acl.extensions] forKey:[NSNumber numberWithInteger:CMISExtensionLevelAcl]];
 
         // Renditions must be converted here, because they need access to the session
         if (objectData.renditions != nil) {
diff --git a/ObjectiveCMIS/Client/CMISSession.h b/ObjectiveCMIS/Client/CMISSession.h
index 053dc1a..c1b18ee 100644
--- a/ObjectiveCMIS/Client/CMISSession.h
+++ b/ObjectiveCMIS/Client/CMISSession.h
@@ -160,6 +160,18 @@
                               progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
 
 /**
+* Downloads the content of object with the provided object id to the given path.
+* completionBlock NSError will be nil if successful
+* Provides options to resume and cancel download
+*/
+- (CMISRequest*)downloadContentOfCMISObject:(NSString *)objectId
+                                     toFile:(NSString *)filePath
+                                     offset:(NSDecimalNumber*)offset
+                                     length:(NSDecimalNumber*)length
+                            completionBlock:(void (^)(NSError *error))completionBlock
+                              progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+/**
  * Downloads the content of object with the provided object id to the given stream.
  * completionBlock NSError will be nil if successful
  */
@@ -168,6 +180,19 @@
                             completionBlock:(void (^)(NSError *error))completionBlock
                               progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
 
+
+/**
+ * Downloads the content of object with the provided object id to the given stream.
+ * completionBlock NSError will be nil if successful
+ * Provides options to resume and cancel download
+ */
+- (CMISRequest*)downloadContentOfCMISObject:(NSString *)objectId
+                             toOutputStream:(NSOutputStream *)outputStream
+                                     offset:(NSDecimalNumber*)offset
+                                     length:(NSDecimalNumber*)length
+                            completionBlock:(void (^)(NSError *error))completionBlock
+                              progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
 /**
  * Creates a cmis document using the content from the file path.
  * completionBlock returns object Id of newly created object or nil if unsuccessful
@@ -177,7 +202,7 @@
                         properties:(NSDictionary *)properties
                           inFolder:(NSString *)folderObjectId
                    completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * Creates a cmis document using the content from the given stream.
@@ -189,5 +214,5 @@
                              inFolder:(NSString *)folderObjectId
                         bytesExpected:(unsigned long long)bytesExpected
                       completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 @end
diff --git a/ObjectiveCMIS/Client/CMISSession.m b/ObjectiveCMIS/Client/CMISSession.m
index 15d94c6..ce686f6 100644
--- a/ObjectiveCMIS/Client/CMISSession.m
+++ b/ObjectiveCMIS/Client/CMISSession.m
@@ -443,9 +443,28 @@
                             completionBlock:(void (^)(NSError *error))completionBlock
                               progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    return [self downloadContentOfCMISObject:objectId
+                                      toFile:filePath
+                                      offset:nil
+                                      length:nil
+                             completionBlock:completionBlock
+                               progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                                   progressBlock(bytesDownloaded, bytesTotal);
+                               }];
+}
+
+- (CMISRequest*)downloadContentOfCMISObject:(NSString *)objectId
+                                     toFile:(NSString *)filePath
+                                     offset:(NSDecimalNumber*)offset
+                                     length:(NSDecimalNumber*)length
+                            completionBlock:(void (^)(NSError *error))completionBlock
+                              progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
     return [self.binding.objectService downloadContentOfObject:objectId
                                                       streamId:nil
                                                         toFile:filePath
+                                                        offset:nil
+                                                        length:nil
                                                completionBlock:completionBlock
                                                  progressBlock:progressBlock];
 }
@@ -455,9 +474,28 @@
                             completionBlock:(void (^)(NSError *error))completionBlock
                               progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    return [self downloadContentOfCMISObject:objectId
+                              toOutputStream:outputStream
+                                      offset:nil
+                                      length:nil
+                             completionBlock:completionBlock
+                               progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+                                   progressBlock(bytesDownloaded, bytesTotal);
+                               }];
+}
+
+- (CMISRequest*)downloadContentOfCMISObject:(NSString *)objectId
+                             toOutputStream:(NSOutputStream *)outputStream
+                                     offset:(NSDecimalNumber*)offset
+                                     length:(NSDecimalNumber*)length
+                            completionBlock:(void (^)(NSError *error))completionBlock
+                              progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
     return [self.binding.objectService downloadContentOfObject:objectId
                                                       streamId:nil
                                                 toOutputStream:outputStream
+                                                        offset:offset
+                                                        length:length
                                                completionBlock:completionBlock
                                                  progressBlock:progressBlock];
 }
@@ -467,7 +505,7 @@
                           mimeType:(NSString *)mimeType
                         properties:(NSDictionary *)properties inFolder:(NSString *)folderObjectId
                    completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     __block CMISRequest *request = [[CMISRequest alloc] init];
     [self.objectConverter convertProperties:properties
@@ -496,7 +534,7 @@
                              inFolder:(NSString *)folderObjectId
                         bytesExpected:(unsigned long long)bytesExpected
                       completionBlock:(void (^)(NSString *objectId, NSError *error))completionBlock
-                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                        progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     __block CMISRequest *request = [[CMISRequest alloc] init];
     [self.objectConverter convertProperties:properties
diff --git a/ObjectiveCMIS/Common/CMISConstants.h b/ObjectiveCMIS/Common/CMISConstants.h
index 1b1a5db..57566d6 100644
--- a/ObjectiveCMIS/Common/CMISConstants.h
+++ b/ObjectiveCMIS/Common/CMISConstants.h
@@ -40,6 +40,8 @@
 extern NSString * const kCMISPropertyChangeToken;
 extern NSString * const kCMISPropertyBaseTypeId;
 extern NSString * const kCMISPropertyCheckinComment;
+extern NSString * const kCMISPropertySecondaryObjectTypeIds;
+extern NSString * const kCMISPropertyDescription;
 // Property values
 extern NSString * const kCMISPropertyObjectTypeIdValueDocument;
 extern NSString * const kCMISPropertyObjectTypeIdValueFolder;
diff --git a/ObjectiveCMIS/Common/CMISConstants.m b/ObjectiveCMIS/Common/CMISConstants.m
index 48ebe27..18c4d46 100644
--- a/ObjectiveCMIS/Common/CMISConstants.m
+++ b/ObjectiveCMIS/Common/CMISConstants.m
@@ -41,6 +41,10 @@
 NSString * const kCMISPropertyChangeToken = @"cmis:changeToken";
 NSString * const kCMISPropertyBaseTypeId = @"cmis:baseTypeId";
 NSString * const kCMISPropertyCheckinComment = @"cmis:checkinComment";
+NSString * const kCMISPropertySecondaryObjectTypeIds = @"cmis:secondaryObjectTypeIds";
+NSString * const kCMISPropertyDescription = @"cmis:description";
+
+
 // Property values
 
 NSString * const kCMISPropertyObjectTypeIdValueDocument = @"cmis:document";
diff --git a/ObjectiveCMIS/Common/CMISEnums.h b/ObjectiveCMIS/Common/CMISEnums.h
index 11dda73..b25a54a 100644
--- a/ObjectiveCMIS/Common/CMISEnums.h
+++ b/ObjectiveCMIS/Common/CMISEnums.h
@@ -120,9 +120,10 @@
 {
     CMISExtensionLevelObject,
     CMISExtensionLevelProperties,
-    CMISExtensionLevelAllowableActions
+    CMISExtensionLevelAllowableActions,
+    CMISExtensionLevelAcl
     // TODO expose the remaining extensions as they are implemented
-    // CMISExtensionLevelAcl, CMISExtensionLevelPolicies, CMISExtensionLevelChangeEvent
+    // CMISExtensionLevelPolicies, CMISExtensionLevelChangeEvent
 
 };
 
diff --git a/ObjectiveCMIS/Common/CMISNetworkProvider.h b/ObjectiveCMIS/Common/CMISNetworkProvider.h
index d01ee87..aad48eb 100644
--- a/ObjectiveCMIS/Common/CMISNetworkProvider.h
+++ b/ObjectiveCMIS/Common/CMISNetworkProvider.h
@@ -92,7 +92,7 @@
  bytesExpected:(unsigned long long)bytesExpected
    cmisRequest:(CMISRequest *)cmisRequest
 completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
- progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 
 /**
@@ -120,7 +120,7 @@
 cmisProperties:(CMISProperties *)cmisProperties
       mimeType:(NSString *)mimeType
 completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
- progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 
 
@@ -146,6 +146,31 @@
 
 
 /**
+ * Invoke method used for downloads,
+ * @param url the RESTful API URL to be used
+ * @param httpRequestMethod
+ * @param session
+ * @param outputStream the stream pointing to the destination. Must be an instance or extension of NSOutputStream
+ * @param bytesExpected the size of the content to be downloaded
+ * @param offset the offset of the stream or null to read the stream from the beginning
+ * @param legnth the maximum length of the stream or null to read to the end of the stream
+ * @param completionBlock returns an instance of the HTTPResponse if successful or nil otherwise
+ * @param progressBlock
+ * @param requestObject a handle to the CMISRequest allowing this HTTP request to be cancelled
+ */
+- (void)invoke:(NSURL *)url
+    httpMethod:(CMISHttpRequestMethod)httpRequestMethod
+       session:(CMISBindingSession *)session
+  outputStream:(NSOutputStream *)outputStream
+ bytesExpected:(unsigned long long)bytesExpected
+        offset:(NSDecimalNumber*)offset
+        length:(NSDecimalNumber*)length
+   cmisRequest:(CMISRequest *)cmisRequest
+completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
+
+/**
  * Convenience GET invoke method
  * @param url the RESTful API URL to be used
  * @param session
diff --git a/ObjectiveCMIS/Common/CMISObjectData.h b/ObjectiveCMIS/Common/CMISObjectData.h
index 3e68120..de589c9 100644
--- a/ObjectiveCMIS/Common/CMISObjectData.h
+++ b/ObjectiveCMIS/Common/CMISObjectData.h
@@ -23,6 +23,7 @@
 #import "CMISAllowableActions.h"
 #import "CMISLinkRelations.h"
 #import "CMISExtensionData.h"
+#import "CMISAcl.h"
 
 @class CMISRenditionData;
 
@@ -34,6 +35,7 @@
 @property (nonatomic, strong) CMISLinkRelations *linkRelations;
 @property (nonatomic, strong) NSURL *contentUrl;
 @property (nonatomic, strong) CMISAllowableActions *allowableActions;
+@property (nonatomic, strong) CMISAcl *acl;
 @property (nonatomic, strong) NSArray *renditions; // An array containing CMISRenditionData objects
 
 @end
diff --git a/ObjectiveCMIS/Utils/CMISDefaultNetworkProvider.m b/ObjectiveCMIS/Utils/CMISDefaultNetworkProvider.m
index 9f0af51..b50a13a 100644
--- a/ObjectiveCMIS/Utils/CMISDefaultNetworkProvider.m
+++ b/ObjectiveCMIS/Utils/CMISDefaultNetworkProvider.m
@@ -101,7 +101,7 @@
  bytesExpected:(unsigned long long)bytesExpected
    cmisRequest:(CMISRequest *)cmisRequest
 completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
- progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     if (!cmisRequest.isCancelled) {
         NSMutableURLRequest *urlRequest = [CMISDefaultNetworkProvider createRequestForUrl:url
@@ -137,7 +137,7 @@
 cmisProperties:(CMISProperties *)cmisProperties
       mimeType:(NSString *)mimeType
 completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
- progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     if (!cmisRequest.isCancelled) {
         NSMutableURLRequest *urlRequest = [CMISDefaultNetworkProvider createRequestForUrl:url
@@ -175,6 +175,22 @@
 completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
  progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
 {
+    [self invoke:url httpMethod:httpRequestMethod session:session outputStream:outputStream bytesExpected:bytesExpected offset:nil length:nil cmisRequest:cmisRequest completionBlock:completionBlock progressBlock:^(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop) {
+        progressBlock(bytesDownloaded, bytesTotal);
+    }];
+}
+
+- (void)invoke:(NSURL *)url
+    httpMethod:(CMISHttpRequestMethod)httpRequestMethod
+       session:(CMISBindingSession *)session
+  outputStream:(NSOutputStream *)outputStream
+ bytesExpected:(unsigned long long)bytesExpected
+        offset:(NSDecimalNumber*)offset
+        length:(NSDecimalNumber*)length
+   cmisRequest:(CMISRequest *)cmisRequest
+completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
+ progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
+{
     if (!cmisRequest.isCancelled) {
         NSMutableURLRequest *urlRequest = [CMISDefaultNetworkProvider createRequestForUrl:url
                                                                                httpMethod:HTTP_GET
@@ -184,6 +200,8 @@
                                                              httpMethod:httpRequestMethod
                                                            outputStream:outputStream
                                                           bytesExpected:bytesExpected
+                                                                 offset:offset
+                                                                 length:length
                                                  authenticationProvider:session.authenticationProvider
                                                         completionBlock:completionBlock
                                                           progressBlock:progressBlock];
diff --git a/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.h b/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.h
index 2e32367..c023a43 100644
--- a/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.h
+++ b/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.h
@@ -41,4 +41,17 @@
                          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
                            progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
 
+/** starts a URL request for download with a given offset and or length. Data are written to the provided output stream
+ * completionBlock returns a CMISHttpResponse object or nil if unsuccessful
+ */
++ (id)startRequest:(NSMutableURLRequest *)urlRequest
+                              httpMethod:(CMISHttpRequestMethod)httpRequestMethod
+                            outputStream:(NSOutputStream*)outputStream
+                           bytesExpected:(unsigned long long)bytesExpected
+                                  offset:(NSDecimalNumber*)offset
+                                  length:(NSDecimalNumber*)length
+                  authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
+                         completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
+                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
+
 @end
diff --git a/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.m b/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.m
index 172bb10..7a20391 100644
--- a/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.m
+++ b/ObjectiveCMIS/Utils/CMISHttpDownloadRequest.m
@@ -23,25 +23,45 @@
 
 @interface CMISHttpDownloadRequest ()
 
-@property (nonatomic, copy) void (^progressBlock)(unsigned long long bytesDownloaded, unsigned long long bytesTotal);
+@property (nonatomic, copy) void (^progressBlock)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop);
 @property (nonatomic, assign) unsigned long long bytesDownloaded;
+@property (nonatomic, assign) BOOL cancelled;
+
 - (id)initWithHttpMethod:(CMISHttpRequestMethod)httpRequestMethod
          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock;
+           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
 
 
 @implementation CMISHttpDownloadRequest
 
++ (id)startRequest:(NSMutableURLRequest *)urlRequest
+        httpMethod:(CMISHttpRequestMethod)httpRequestMethod
+      outputStream:(NSOutputStream*)outputStream
+     bytesExpected:(unsigned long long)bytesExpected
+authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
+   completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
+     progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
+{
+    return [CMISHttpDownloadRequest startRequest:urlRequest
+                               httpMethod:httpRequestMethod
+                             outputStream:outputStream
+                            bytesExpected:bytesExpected
+                   authenticationProvider:authenticationProvider
+                          completionBlock:completionBlock
+                            progressBlock:progressBlock];
+}
 
 + (id)startRequest:(NSMutableURLRequest *)urlRequest
                               httpMethod:(CMISHttpRequestMethod)httpRequestMethod
                             outputStream:(NSOutputStream*)outputStream
                            bytesExpected:(unsigned long long)bytesExpected
+                                  offset:(NSDecimalNumber*)offset
+                                  length:(NSDecimalNumber*)length
                   authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
                          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
+                           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     CMISHttpDownloadRequest *httpRequest = [[self alloc] initWithHttpMethod:httpRequestMethod
                                                             completionBlock:completionBlock
@@ -50,6 +70,21 @@
     httpRequest.bytesExpected = bytesExpected;
     httpRequest.authenticationProvider = authenticationProvider;
     
+    //range
+    if ((offset != nil) || (length != nil)) {
+        if (offset == nil) {
+            offset = [NSDecimalNumber zero];
+        }
+        
+        NSMutableString *range = [NSMutableString stringWithFormat:@"bytes=%@-",[offset stringValue]];
+        
+        if ((length != nil) && ([length longLongValue] >= 1)) {
+            [range appendFormat:@"%llu", [offset unsignedLongLongValue] + [length unsignedLongLongValue] - 1];
+        }
+        
+        httpRequest.additionalHeaders = [NSDictionary dictionaryWithObject:range forKey:@"Range"];
+    }
+
     if (![httpRequest startRequest:urlRequest]) {
         httpRequest = nil;
     };
@@ -60,7 +95,7 @@
 
 - (id)initWithHttpMethod:(CMISHttpRequestMethod)httpRequestMethod
          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal))progressBlock
+           progressBlock:(void (^)(unsigned long long bytesDownloaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     self = [super initWithHttpMethod:httpRequestMethod
                      completionBlock:completionBlock];
@@ -138,7 +173,13 @@
     self.bytesDownloaded += data.length;
     // pass progress to progressBlock
     if (self.progressBlock) {
-        self.progressBlock(self.bytesDownloaded, self.bytesExpected);
+        BOOL cancelled = NO;
+        self.progressBlock(self.bytesDownloaded, self.bytesExpected, &cancelled);
+        
+        // Cancel Download Request if requested
+        if (cancelled == YES) {
+            [self cancel];
+        }
     }
     
 }
diff --git a/ObjectiveCMIS/Utils/CMISHttpRequest.m b/ObjectiveCMIS/Utils/CMISHttpRequest.m
index 95cd9a1..10b6a71 100644
--- a/ObjectiveCMIS/Utils/CMISHttpRequest.m
+++ b/ObjectiveCMIS/Utils/CMISHttpRequest.m
@@ -198,7 +198,7 @@
         CMISLogTrace(@"Response body: %@", [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]);
     }
     
-    if ( (httpRequestMethod == HTTP_GET && response.statusCode != 200)
+    if ( (httpRequestMethod == HTTP_GET && response.statusCode != 200 && response.statusCode != 206)
         || (httpRequestMethod == HTTP_POST && response.statusCode != 201)
         || (httpRequestMethod == HTTP_DELETE && response.statusCode != 204)
         || (httpRequestMethod == HTTP_PUT && ((response.statusCode < 200 || response.statusCode > 299)))) {
diff --git a/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h b/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h
index 921e16d..3459392 100644
--- a/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h
+++ b/ObjectiveCMIS/Utils/CMISHttpUploadRequest.h
@@ -36,7 +36,7 @@
                          bytesExpected:(unsigned long long)bytesExpected
                 authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
                        completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-                         progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+                         progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 /**
  * starts a URL request with a provided input stream. The input stream has to point to the raw NON-encoded data set. This method will use the
@@ -54,6 +54,6 @@
     cmisProperties:(CMISProperties *)cmisProperties
           mimeType:(NSString *)mimeType
    completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
diff --git a/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m b/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m
index 97a7dde..b9abc26 100644
--- a/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m
+++ b/ObjectiveCMIS/Utils/CMISHttpUploadRequest.m
@@ -27,6 +27,8 @@
 #import "CMISBase64Encoder.h"
 #import "CMISAtomEntryWriter.h"
 #import "CMISLog.h"
+#import "CMISErrors.h"
+
 /**
  this is the buffer size for the input/output stream pair containing the base64 encoded data
  */
@@ -82,7 +84,7 @@
 @interface CMISHttpUploadRequest ()
 
 @property (nonatomic, assign) unsigned long long bytesUploaded;
-@property (nonatomic, copy) void (^progressBlock)(unsigned long long bytesUploaded, unsigned long long bytesTotal);
+@property (nonatomic, copy) void (^progressBlock)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop);
 @property (nonatomic, assign) BOOL base64Encoding;
 @property (nonatomic, strong) NSInputStream *base64InputStream;
 @property (nonatomic, strong) NSOutputStream *encoderStream;
@@ -100,7 +102,7 @@
 
 - (id)initWithHttpMethod:(CMISHttpRequestMethod)httpRequestMethod
          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-           progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock;
+           progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock;
 
 @end
 
@@ -114,7 +116,7 @@
                          bytesExpected:(unsigned long long)bytesExpected
                 authenticationProvider:(id<CMISAuthenticationProvider>) authenticationProvider
                        completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-                         progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+                         progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     CMISHttpUploadRequest *httpRequest = [[self alloc] initWithHttpMethod:httpRequestMethod
                                                           completionBlock:completionBlock
@@ -143,7 +145,7 @@
     cmisProperties:(CMISProperties *)cmisProperties
           mimeType:(NSString *)mimeType
    completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+     progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     CMISHttpUploadRequest *httpRequest = [[self alloc] initWithHttpMethod:httpRequestMethod
                                                           completionBlock:completionBlock
@@ -167,7 +169,7 @@
 
 - (id)initWithHttpMethod:(CMISHttpRequestMethod)httpRequestMethod
          completionBlock:(void (^)(CMISHttpResponse *httpResponse, NSError *error))completionBlock
-           progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal))progressBlock
+           progressBlock:(void (^)(unsigned long long bytesUploaded, unsigned long long bytesTotal, BOOL *stop))progressBlock
 {
     self = [super initWithHttpMethod:httpRequestMethod
                      completionBlock:completionBlock];
@@ -241,10 +243,17 @@
             }
         }
         
+        BOOL cancelled = NO;
         if (self.bytesExpected == 0) {
-            self.progressBlock((unsigned long long)totalBytesWritten, (unsigned long long)totalBytesExpectedToWrite);
+            self.progressBlock((unsigned long long)totalBytesWritten, (unsigned long long)totalBytesExpectedToWrite, &cancelled);
         } else {
-            self.progressBlock((unsigned long long)totalBytesWritten, self.bytesExpected);
+            self.progressBlock((unsigned long long)totalBytesWritten, self.bytesExpected, &cancelled);
+        }
+        
+        // Cancel Upload Request if requested
+        if (cancelled == YES) {
+            [self cancel];
+            self.progressBlock((unsigned long long)totalBytesWritten, self.bytesExpected, &cancelled);
         }
     }
 }
@@ -385,6 +394,8 @@
                 bytesWritten = [self.encoderStream write:&buffer[self.bufferOffset] maxLength:self.bufferLimit - self.bufferOffset];
                 if (bytesWritten <= 0) {
                     [self stopSendWithStatus:@"Network write error"];
+                    NSError *cmisError = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeConnection detailedDescription:@"Network write error"];
+                    [self connection:nil didFailWithError:cmisError];
                 } else {
                     self.bufferOffset += bytesWritten;
                 }
@@ -430,8 +441,8 @@
     self.streamEndData = [end dataUsingEncoding:NSUTF8StringEncoding];
     
     unsigned long long encodedLength = [CMISHttpUploadRequest base64EncodedLength:self.bytesExpected];
-    encodedLength += start.length;
-    encodedLength += end.length;
+    encodedLength += self.streamStartData.length;
+    encodedLength += self.streamEndData.length;
     self.encodedLength = encodedLength;
 }
 
diff --git a/ObjectiveCMIS/Utils/CMISObjectConverter.m b/ObjectiveCMIS/Utils/CMISObjectConverter.m
index 43ddc48..60878fd 100644
--- a/ObjectiveCMIS/Utils/CMISObjectConverter.m
+++ b/ObjectiveCMIS/Utils/CMISObjectConverter.m
@@ -25,6 +25,7 @@
 #import "CMISPropertyDefinition.h"
 #import "CMISSession.h"
 #import "CMISDateUtil.h"
+#import "CMISConstants.h"
 
 @interface CMISObjectConverter ()
 @property (nonatomic, weak) CMISSession *session;
@@ -63,15 +64,19 @@
 {
     [self convertObject:[objectDatas objectAtIndex:position]
         completionBlock:^(CMISObject *object, NSError *error) {
-            if (position == 0) {
-                NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:objectDatas.count];
-                [objects addObject:object];
-                completionBlock(objects, error);
+            if(error){
+                completionBlock(nil, error);
             } else {
-                [self internalConvertObject:objectDatas position:(position - 1) completionBlock:^(NSMutableArray *objects, NSError *error) {
+                if (position == 0) {
+                    NSMutableArray *objects = [[NSMutableArray alloc] initWithCapacity:objectDatas.count];
                     [objects addObject:object];
                     completionBlock(objects, error);
-                }];
+                } else {
+                    [self internalConvertObject:objectDatas position:(position - 1) completionBlock:^(NSMutableArray *objects, NSError *error) {
+                        [objects addObject:object];
+                        completionBlock(objects, error);
+                    }];
+                }
             }
         }];
 }
@@ -99,8 +104,15 @@
 }
 
 
-- (void)internalNormalConvertProperties:(NSDictionary *)properties 
-                         typeDefinition:(CMISTypeDefinition *)typeDefinition 
+- (void)internalNormalConvertProperties:(NSDictionary *)properties
+                         typeDefinition:(CMISTypeDefinition *)typeDefinition
+                        completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
+{
+    [self internalNormalConvertProperties:properties typeDefinitions:[NSArray arrayWithObject:typeDefinition] completionBlock:completionBlock];
+}
+
+- (void)internalNormalConvertProperties:(NSDictionary *)properties
+                         typeDefinitions:(NSArray *)typeDefinitions
                         completionBlock:(void (^)(CMISProperties *convertedProperties, NSError *error))completionBlock
 {
     CMISProperties *convertedProperties = [[CMISProperties alloc] init];
@@ -111,7 +123,7 @@
             [convertedProperties addProperty:(CMISPropertyData *)propertyValue];
         } else {
             // Convert to CMISPropertyData based on the string
-            CMISPropertyDefinition *propertyDefinition = [typeDefinition propertyDefinitionForId:propertyId];
+            CMISPropertyDefinition *propertyDefinition = [self propertyDefinitionFromTypeDefinitions:typeDefinitions propertyId:propertyId];
             
             if (propertyDefinition == nil) {
                 NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
@@ -310,6 +322,18 @@
     completionBlock(convertedProperties, nil);
 }
 
+-(CMISPropertyDefinition*)propertyDefinitionFromTypeDefinitions:(NSArray *)typeDefinitions propertyId:(NSString*)propertyId
+{
+    for (CMISTypeDefinition* typeDefinition in typeDefinitions) {
+        CMISPropertyDefinition *propertyDefinition = [typeDefinition propertyDefinitionForId:propertyId];
+        
+        if (propertyDefinition) {
+            return propertyDefinition;
+        }
+    }
+    return nil;
+}
+
 
 - (void)internalNormalConvertProperties:(NSDictionary *)properties
                            objectTypeId:(NSString *)objectTypeId
@@ -346,16 +370,94 @@
                               completionBlock:completionBlock];
         
     } else {
-        [self.session retrieveTypeDefinition:objectTypeId
-                             completionBlock:^(CMISTypeDefinition *typeDefinition, NSError *error) {
-                                 if (error) {
-                                     completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
-                                 } else {
-                                     [self internalNormalConvertProperties:properties
-                                                            typeDefinition:typeDefinition
-                                                           completionBlock:completionBlock];
-                                 }
-                             }];
+        
+        //get secondary object type definitions - if available
+        NSString *propertyId = kCMISPropertySecondaryObjectTypeIds;
+        id secondaryObjectTypeIds = [properties valueForKey:propertyId];
+        if(secondaryObjectTypeIds) {
+            Class expectedType = nil;
+            BOOL validType = YES;
+            
+            //verify types
+            expectedType = [NSArray class];
+            if([secondaryObjectTypeIds isKindOfClass:expectedType]){
+                expectedType = [NSString class];
+                for (id secondaryObjectTypeId in secondaryObjectTypeIds) {
+                    propertyId = secondaryObjectTypeId;
+                    if(![secondaryObjectTypeId isKindOfClass:expectedType]){
+                        validType = NO;
+                        break;
+                    }
+                }
+            } else {
+                validType = NO;
+            }
+            
+            if (!validType) {
+                NSError *error = [CMISErrors createCMISErrorWithCode:kCMISErrorCodeInvalidArgument
+                                                 detailedDescription:[NSString stringWithFormat:@"Property value for %@ should be of type '%@'", propertyId, expectedType]];
+                completionBlock(nil, error);
+                return;
+            }
+            
+            NSMutableArray *objectTypeIds = [NSMutableArray arrayWithObject:objectTypeId];
+            [objectTypeIds addObjectsFromArray:secondaryObjectTypeIds];
+            [self retrieveTypeDefinitions:objectTypeIds
+                          completionBlock:^(NSArray *typeDefinitions, NSError *error) {
+                              if (error) {
+                                  completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
+                              } else {
+                                  [self internalNormalConvertProperties:properties
+                                                         typeDefinitions:typeDefinitions
+                                                        completionBlock:completionBlock];
+                              }
+            }];
+        } else {
+            [self.session retrieveTypeDefinition:objectTypeId
+                                 completionBlock:^(CMISTypeDefinition *typeDefinition, NSError *error) {
+                                     if (error) {
+                                         completionBlock(nil, [CMISErrors cmisError:error cmisErrorCode:kCMISErrorCodeRuntime]);
+                                     } else {
+                                         [self internalNormalConvertProperties:properties
+                                                                typeDefinition:typeDefinition
+                                                               completionBlock:completionBlock];
+                                     }
+                                 }];
+        }
+    }
+}
+
+- (void)retrieveTypeDefinitions:(NSArray *)objectTypeIds position:(NSInteger)position completionBlock:(void (^)(NSMutableArray *typeDefinitions, NSError *error))completionBlock
+{
+    [self.session retrieveTypeDefinition:[objectTypeIds objectAtIndex:position]
+                         completionBlock:^(CMISTypeDefinition *typeDefinition, NSError *error) {
+            if(error){
+                completionBlock(nil, error);
+            } else {
+                if (position == 0) {
+                    NSMutableArray *typeDefinitions = [[NSMutableArray alloc] initWithCapacity:objectTypeIds.count];
+                    [typeDefinitions addObject:typeDefinition];
+                    completionBlock(typeDefinitions, error);
+                } else {
+                    [self retrieveTypeDefinitions:objectTypeIds position:(position - 1) completionBlock:^(NSMutableArray *typeDefinitions, NSError *error) {
+                        [typeDefinitions addObject:typeDefinition];
+                        completionBlock(typeDefinitions, error);
+                    }];
+                }
+            }
+        }];
+}
+
+- (void)retrieveTypeDefinitions:(NSArray *)objectTypeIds completionBlock:(void (^)(NSArray *typeDefinitions, NSError *error))completionBlock
+{
+    if (objectTypeIds.count > 0) {
+        [self retrieveTypeDefinitions:objectTypeIds
+                           position:(objectTypeIds.count - 1) // start recursion with last item
+                    completionBlock:^(NSMutableArray *typeDefinitions, NSError *error) {
+                        completionBlock(typeDefinitions, error);
+                    }];
+    } else {
+        completionBlock([[NSArray alloc] init], nil);
     }
 }