Permalink
Browse files

Support custom headers to send in replication requests.

Added property .headers to CouchReplication & CouchPersistentReplication.
Removed properties .source and .target from CouchPersistentReplication; these are problematic because they're directly mapped
to the replication document, where their values can be either strings or dictionaries.
Instead, use properties .remoteURL and .localDatabase to find the endpoints.

Change-Id: I0cff66b8c0505e484787e3b19b2c8d7a3f11419d
  • Loading branch information...
1 parent 6838c8d commit 71199c9a8082bbd13b6e9c8e198831e5a60bb35c @snej snej committed May 21, 2012
View
@@ -76,6 +76,13 @@ typedef void (^OnDatabaseChangeBlock)(CouchDocument*, BOOL externalChange);
@end
+@interface CouchPersistentReplication ()
+@property (readonly) NSString* sourceURLStr;
+@property (readonly) NSString* targetURLStr;
+@end
+
+
+
@interface CouchServer ()
@property (readonly) BOOL isEmbeddedServer;
- (CouchPersistentReplication*) replicationWithSource: (NSString*)source
@@ -32,16 +32,15 @@ typedef enum {
CouchReplicationMode _mode;
}
-/** The source URL for the replication.
- This will be either a complete HTTP(s) URL or the name of a database on this server. */
-@property (readonly, copy) NSString* source;
-
-/** The destination URL for the replication.
- This will be either a complete HTTP(s) URL or the name of a database on this server. */
-@property (readonly, copy) NSString* target;
+/** The local database being replicated to/from. */
+@property (readonly) CouchDatabase* localDatabase;
+/** The remote database being replicated to/from. */
@property (readonly) NSURL* remoteURL;
+/** Does the replication pull from (as opposed to push to) the target? */
+@property (nonatomic, readonly) bool pull;
+
/** Should the target database be created if it doesn't already exist? (Defaults to NO). */
@property bool create_target;
@@ -60,6 +59,10 @@ typedef enum {
/** Sets the documents to specify as part of the replication. */
@property (copy) NSArray *doc_ids;
+/** Extra HTTP headers to send in all requests to the remote server.
+ Should map strings (header names) to strings. */
+@property (copy) NSDictionary* headers;
+
/** Sets the "user_ctx" property of the replication, which identifies what privileges it will run with when accessing the local server. To replicate design documents, this should be set to a value with "_admin" in the list of roles.
The server will not let you specify privileges you don't have, so the request to create the replication must be made with credentials that match what you're setting here, unless the server is in no-authentication "admin party" mode.
See <https://gist.github.com/832610>, section 8, for details.
@@ -18,6 +18,8 @@
@interface CouchPersistentReplication ()
+@property (copy) id source;
+@property (copy) id target;
@property (readwrite) CouchReplicationState state;
@property (nonatomic, readwrite, retain) NSError* error;
@property (nonatomic, readwrite) CouchReplicationMode mode;
@@ -38,8 +40,8 @@ + (CouchPersistentReplication*) createWithReplicatorDatabase: (CouchDatabase*)re
{
CouchPersistentReplication* rep = [[self alloc] initWithNewDocumentInDatabase: replicatorDB];
rep.autosaves = YES;
- [rep setValue: source ofProperty: @"source"];
- [rep setValue: target ofProperty: @"target"];
+ rep.source = source;
+ rep.target = target;
return [rep autorelease];
}
@@ -75,14 +77,74 @@ - (void) actAsAdmin {
}
+static inline BOOL isLocalDBName(NSString* url) {
+ return [url rangeOfString: @":"].length == 0;
+}
+
+
+- (NSString*) sourceURLStr {
+ id source = self.source;
+ if ([source isKindOfClass: [NSDictionary class]])
+ source = [source objectForKey: @"url"];
+ return $castIf(NSString, source);
+}
+
+
+- (NSString*) targetURLStr {
+ id target = self.target;
+ if ([target isKindOfClass: [NSDictionary class]])
+ target = [target objectForKey: @"url"];
+ return $castIf(NSString, target);
+}
+
+
+- (bool) pull {
+ return isLocalDBName(self.targetURLStr);
+}
+
+
+- (CouchDatabase*) localDatabase {
+ NSString* name = self.sourceURLStr;
+ if (!isLocalDBName(name))
+ name = self.targetURLStr;
+ return [self.database.server databaseNamed: name];
+}
+
+
- (NSURL*) remoteURL {
- NSString* urlStr = self.source;
- if ([urlStr rangeOfString: @":"].length == 0)
- urlStr = self.target;
+ NSString* urlStr = self.sourceURLStr;
+ if (isLocalDBName(urlStr))
+ urlStr = self.targetURLStr;
return [NSURL URLWithString: urlStr];
}
+- (NSDictionary*) headers {
+ id source = self.source;
+ if ([source isKindOfClass: [NSDictionary class]]
+ && !isLocalDBName([source objectForKey: @"url"]))
+ return [source objectForKey: @"headers"];
+ id target = self.target;
+ if ([target isKindOfClass: [NSDictionary class]]
+ && !isLocalDBName([target objectForKey: @"url"]))
+ return [target objectForKey: @"headers"];
+ return nil;
+}
+
+
+- (void) setHeaders: (NSDictionary*)headers {
+ BOOL isPull = self.pull;
+ id remote = isPull ? self.source : self.target;
+ if ([remote isKindOfClass: [NSString class]])
+ remote = [NSMutableDictionary dictionaryWithObject: remote forKey: @"url"];
+ [remote setValue: headers forKey: @"headers"];
+ if (isPull)
+ self.source = remote;
+ else
+ self.target = remote;
+}
+
+
- (CouchReplicationState) state {
return _state;
}
View
@@ -35,6 +35,7 @@ typedef enum {
NSString* _filter;
NSDictionary* _filterParams;
NSDictionary* _options;
+ NSDictionary* _headers;
BOOL _running;
NSString* _taskID;
NSString* _status;
@@ -43,6 +44,15 @@ typedef enum {
NSError* _error;
}
+/** The local database being replicated to/from. */
+@property (nonatomic, readonly) CouchDatabase* localDatabase;
+
+/** The URL of the remote database. */
+@property (nonatomic, readonly) NSURL* remoteURL;
+
+/** Does the replication pull from (as opposed to push to) the target? */
+@property (nonatomic, readonly) bool pull;
+
/** Should the target database be created if it doesn't already exist? (Defaults to NO). */
@property (nonatomic) bool createTarget;
@@ -58,6 +68,10 @@ typedef enum {
Should be a JSON-compatible dictionary. */
@property (nonatomic, copy) NSDictionary* filterParams;
+/** Extra HTTP headers to send in all requests to the remote server.
+ Should map strings (header names) to strings. */
+@property (nonatomic, copy) NSDictionary* headers;
+
/** Other options to be provided to the replicator.
These will be added to the JSON body of the POST to /_replicate. */
@property (nonatomic, copy) NSDictionary* options;
@@ -70,11 +84,6 @@ typedef enum {
/** Stops replication, asynchronously. */
- (void) stop;
-@property (nonatomic, readonly) NSURL* remoteURL;
-
-/** Does the replication pull from (as opposed to push to) the target? */
-@property (nonatomic, readonly) bool pull;
-
@property (nonatomic, readonly) BOOL running;
/** The current status string from the server, if active, else nil (observable).
View
@@ -62,6 +62,7 @@ - (void)dealloc {
[_filter release];
[_filterParams release];
[_options release];
+ [_headers release];
[super dealloc];
}
@@ -73,12 +74,21 @@ - (NSString*) description {
@synthesize pull=_pull, createTarget=_createTarget, continuous=_continuous,
- filter=_filter, filterParams=_filterParams, options=_options;
+ filter=_filter, filterParams=_filterParams, options=_options, headers=_headers,
+ localDatabase=_database;
- (RESTOperation*) operationToStart: (BOOL)start {
- NSString* source = _pull ? _remote.absoluteString : _database.relativePath;
- NSString* target = _pull ? _database.relativePath : _remote.absoluteString;
+ id source = _pull ? _remote.absoluteString : _database.relativePath;
+ id target = _pull ? _database.relativePath : _remote.absoluteString;
+ if (_headers.count > 0) {
+ // Convert 'source' or 'target' to a dictionary so we can add 'headers' to it:
+ id *param = _pull ? &source : &target;
+ *param = [NSDictionary dictionaryWithObjectsAndKeys:
+ *param, @"url",
+ _headers, @"headers",
+ nil];
+ }
NSMutableDictionary* body = [NSMutableDictionary dictionaryWithObjectsAndKeys:
source, @"source",
target, @"target",
View
@@ -151,7 +151,7 @@ - (CouchPersistentReplication*) replicationWithSource: (NSString*)source
target: (NSString*)target
{
for (CouchPersistentReplication* repl in self.replications) {
- if ($equal(repl.source, source) && $equal(repl.target, target))
+ if ($equal(repl.sourceURLStr, source) && $equal(repl.targetURLStr, target))
return repl;
}
return [CouchPersistentReplication createWithReplicatorDatabase: self.replicatorDatabase

0 comments on commit 71199c9

Please sign in to comment.