Skip to content

Commit

Permalink
Fixed incompatibility with CouchDB's _changes feed
Browse files Browse the repository at this point in the history
CouchDB also supports POST to _changes but expects most of the parameters
to still be in the URL, not the request body.

Fixes #1139
  • Loading branch information
snej committed Apr 14, 2016
1 parent 9e635d3 commit 80901c3
Showing 1 changed file with 31 additions and 25 deletions.
56 changes: 31 additions & 25 deletions Source/ChangeTracker/CBLChangeTracker.m
Expand Up @@ -93,9 +93,10 @@ - (NSString*) feed {
}

- (NSString*) changesFeedPath {
if (_usePOST)
return @"_changes";

// We add the basic query params to the URL even if we'll send a POST request. Yes, this is
// redundant, since those params are in the JSON body too. This is for CouchDB compatibility:
// for some reason it still expects most of the params in the URL, even with a POST; only the
// filter-related params go in the body. (See #1139)
NSMutableString* path;
path = [NSMutableString stringWithFormat: @"_changes?feed=%@&heartbeat=%.0f",
self.feed, _heartbeat*1000.0];
Expand All @@ -113,30 +114,32 @@ - (NSString*) changesFeedPath {
if (_limit > 0)
[path appendFormat: @"&limit=%u", _limit];

// Add filter or doc_ids:
NSString* filterName = _filterName;
NSDictionary* filterParameters = _filterParameters;
if (_docIDs) {
filterName = @"_doc_ids";
filterParameters = @{@"doc_ids": _docIDs};
}
if (filterName) {
[path appendFormat: @"&filter=%@", CBLEscapeURLParam(filterName)];
for (NSString* key in filterParameters) {
NSString* value = filterParameters[key];
if (![value isKindOfClass: [NSString class]]) {
// It's ambiguous whether non-string filter params are allowed.
// If we get one, encode it as JSON:
NSError* error;
value = [CBLJSON stringWithJSONObject: value options: CBLJSONWritingAllowFragments
error: &error];
if (!value) {
Warn(@"Illegal filter parameter %@ = %@", key, filterParameters[key]);
continue;
if (!_usePOST) {
// Add filter or doc_ids to URL. If sending a POST, these will go in the JSON body instead.
NSString* filterName = _filterName;
NSDictionary* filterParameters = _filterParameters;
if (_docIDs) {
filterName = @"_doc_ids";
filterParameters = @{@"doc_ids": _docIDs};
}
if (filterName) {
[path appendFormat: @"&filter=%@", CBLEscapeURLParam(filterName)];
for (NSString* key in filterParameters) {
NSString* value = filterParameters[key];
if (![value isKindOfClass: [NSString class]]) {
// It's ambiguous whether non-string filter params are allowed.
// If we get one, encode it as JSON:
NSError* error;
value = [CBLJSON stringWithJSONObject: value options: CBLJSONWritingAllowFragments
error: &error];
if (!value) {
Warn(@"Illegal filter parameter %@ = %@", key, filterParameters[key]);
continue;
}
}
[path appendFormat: @"&%@=%@", CBLEscapeURLParam(key),
CBLEscapeURLParam(value)];
}
[path appendFormat: @"&%@=%@", CBLEscapeURLParam(key),
CBLEscapeURLParam(value)];
}
}

Expand All @@ -161,6 +164,9 @@ - (NSData*) changesFeedPOSTBody {
filterName = @"_doc_ids";
filterParameters = @{@"doc_ids": _docIDs};
}
// Sync Gateway expects all the parameters here, but CouchDB expects them in the URL and
// ignores these, _except_ the filter and filterParameters. For compatibility we put the
// basic parameters in both places.
NSMutableDictionary* post = $mdict({@"feed", self.feed},
{@"heartbeat", @(round(_heartbeat*1000.0))},
{@"style", (_includeConflicts ? @"all_docs" : nil)},
Expand Down

0 comments on commit 80901c3

Please sign in to comment.