Skip to content

Commit

Permalink
Fixes #796
Browse files Browse the repository at this point in the history
Closes #776
  • Loading branch information
borrrden committed Jan 7, 2017
1 parent c24738e commit 16af81f
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 57 deletions.
8 changes: 4 additions & 4 deletions src/Couchbase.Lite.Shared/Replication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -604,14 +604,14 @@ internal IHttpClientFactory ClientFactory {
/// <summary>
/// Gets or sets the headers that should be used when making HTTP requests
/// </summary>
[Obsolete("Use Headers")]
[Obsolete("Use Headers, this method will throw an exception")]
protected internal IDictionary<string, object> RequestHeaders
{
get {
return _remoteSession.RequestHeaders;
throw new NotSupportedException();
}
set {
_remoteSession.RequestHeaders = value ?? new Dictionary<string, object>();
set {
throw new NotSupportedException();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ internal class CouchbaseLiteHttpClientFactory : IHttpClientFactory
public CouchbaseLiteHttpClientFactory()
{
SocketTimeout = ReplicationOptions.DefaultSocketTimeout;
Headers = new ConcurrentDictionary<string, string>();
}

internal static void SetupSslCallback()
Expand Down Expand Up @@ -196,13 +195,6 @@ public CouchbaseLiteHttpClient GetHttpClient(CookieStore cookieStore, IRetryStra
client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", String.Format("CouchbaseLite/{0} ({1})", Replication.SyncProtocolVersion, Manager.VersionString));
client.DefaultRequestHeaders.Connection.Add("keep-alive");

foreach(var header in Headers)
{
var success = client.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
if (!success)
Log.To.Sync.W(Tag, String.Format("Unabled to add header to request: {0}: {1}", header.Key, header.Value));
}

var transientHandler = authHandler as TransientErrorRetryHandler;
var defaultAuthHandler = default(DefaultAuthHandler);
if (transientHandler != null) {
Expand All @@ -213,8 +205,6 @@ public CouchbaseLiteHttpClient GetHttpClient(CookieStore cookieStore, IRetryStra

return new CouchbaseLiteHttpClient(client, defaultAuthHandler);
}

public IDictionary<string, string> Headers { get; set; }

}
}
11 changes: 7 additions & 4 deletions src/Couchbase.Lite.Shared/Replication/Puller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -739,10 +739,13 @@ private void InsertDownloads(IList<RevisionInternal> downloads)

public override IEnumerable<string> DocIds { get; set; }

public override IDictionary<string, string> Headers
{
get { return ClientFactory.Headers; }
set { ClientFactory.Headers = value; }
public override IDictionary<string, string> Headers {
get {
return _remoteSession.RequestHeaders;
}
set {
_remoteSession.RequestHeaders = value;
}
}

protected override void Retry()
Expand Down
12 changes: 8 additions & 4 deletions src/Couchbase.Lite.Shared/Replication/Pusher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -572,11 +572,15 @@ private void PurgeRevs(IList<RevisionInternal> revs)

#region Overrides

public override IEnumerable<String> DocIds { get; set; }
public override IEnumerable<string> DocIds { get; set; }

public override IDictionary<String, String> Headers {
get { return ClientFactory.Headers; }
set { ClientFactory.Headers = value; }
public override IDictionary<string, string> Headers {
get {
return _remoteSession.RequestHeaders;
}
set {
_remoteSession.RequestHeaders = value;
}
}

public override Boolean CreateTarget { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion src/Couchbase.Lite.Shared/Replication/RemoteSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ internal sealed class RemoteSession : IDisposable

public RemoteServerVersion ServerType { get; set; }

public IDictionary<string, object> RequestHeaders { get; set; } = new Dictionary<string, object>();
public IDictionary<string, string> RequestHeaders { get; set; } = new Dictionary<string, string>();

public bool Disposed { get; private set; }

Expand Down
13 changes: 10 additions & 3 deletions src/Couchbase.Lite.Shared/Replication/WebSocketChangeTracker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,17 @@ public override bool Start()
_client.SetCookie(new WebSocketSharp.Net.Cookie(cookie.Name, cookie.Value, cookie.Path, cookie.Domain));
}

var additionalHeaders = new Dictionary<string, string>();
if (authHeader != null) {
_client.CustomHeaders = new Dictionary<string, string> {
["Authorization"] = authHeader.ToString()
};
additionalHeaders["Authorization"] = authHeader.ToString();
}

foreach(var header in _remoteSession.RequestHeaders) {
additionalHeaders[header.Key] = header.Value;
}

if(additionalHeaders.Any()) {
_client.CustomHeaders = additionalHeaders;
}

_client.ConnectAsync();
Expand Down
6 changes: 0 additions & 6 deletions src/Couchbase.Lite.Shared/Util/IHttpClientFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,6 @@ internal interface IHttpClientFactory
// Create an HTTP client based on the cookie store
CouchbaseLiteHttpClient GetHttpClient(CookieStore cookieStore, IRetryStrategy retryStrategy);

/// <summary>
/// Gets or sets the headers used by default in the HttpClient
/// </summary>
/// <value>The headers.</value>
IDictionary<string,string> Headers { get; set; }

TimeSpan SocketTimeout { get; set; }
}
}
Expand Down
87 changes: 62 additions & 25 deletions src/Couchbase.Lite.Tests.Shared/ReplicationTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1830,55 +1830,92 @@ public virtual void TestChannelsMore()
[Test]
public void TestHeaders()
{
if (!Boolean.Parse((string)GetProperty("replicationTestsEnabled")))
{
if(!Boolean.Parse((string)GetProperty("replicationTestsEnabled"))) {
Assert.Inconclusive("Replication tests disabled.");
return;
}

var mockHttpClientFactory = new MockHttpClientFactory(false);
manager.DefaultHttpClientFactory = mockHttpClientFactory;
database.GetDocument("doc1").PutProperties(new Dictionary<string, object> {
["jim"] = "borden"
});

var mockHttpHandler = mockHttpClientFactory.HttpHandler;
database.GetDocument("doc2").PutProperties(new Dictionary<string, object> {
["foo"] = "bar"
});

using (var remoteDb = _sg.CreateDatabase(TempDbName())) {
using(var remoteDb = _sg.CreateDatabase(TempDbName())) {
var remote = remoteDb.RemoteUri;
var puller = database.CreatePullReplication(remote);
var headers = new Dictionary<string, string>();
headers["foo"] = "bar";

var pusher = database.CreatePushReplication (remote);
pusher.Headers = headers;
pusher.Start ();
Sleep (5000);
pusher.Stop ();
var mockHttpClientFactory = new MockHttpClientFactory(false);
var mockHttpHandler = mockHttpClientFactory.HttpHandler;
var pusher = database.CreatePushReplication(remote);
pusher.ClientFactory = mockHttpClientFactory;
pusher.Headers.Add("foo", "bar");
pusher.Start();
Sleep(2000);
pusher.Stop();

ValidateHttpHeaders (mockHttpHandler);
mockHttpHandler.ClearCapturedRequests ();
ValidateHttpHeaders(mockHttpHandler);
mockHttpHandler.ClearCapturedRequests();

puller.Headers = headers;
mockHttpClientFactory = new MockHttpClientFactory(false);
mockHttpHandler = mockHttpClientFactory.HttpHandler;
puller.ClientFactory = mockHttpClientFactory;
puller.Headers.Add("foo", "bar");
puller.Start();
Sleep(5000);
Sleep(2000);
puller.Stop();

ValidateHttpHeaders (mockHttpHandler);
ValidateHttpHeaders(mockHttpHandler);
mockHttpHandler.ClearCapturedRequests();

mockHttpClientFactory = new MockHttpClientFactory(false);
mockHttpHandler = mockHttpClientFactory.HttpHandler;
pusher = database.CreatePushReplication(remote);
pusher.ClientFactory = mockHttpClientFactory;
pusher.Continuous = true;
pusher.Headers.Add("foo", "bar");
pusher.Start();
Sleep(2000);
pusher.Stop();

ValidateHttpHeaders(mockHttpHandler);
mockHttpHandler.ClearCapturedRequests();

mockHttpClientFactory = new MockHttpClientFactory(false);
mockHttpHandler = mockHttpClientFactory.HttpHandler;
puller = database.CreatePullReplication(remote);
puller.ClientFactory = mockHttpClientFactory;
puller.Continuous = true;
puller.Headers.Add("foo", "bar");
puller.Start();
Sleep(2000);
puller.Stop();

ValidateHttpHeaders(mockHttpHandler);
}
}

private void ValidateHttpHeaders (MockHttpRequestHandler mockHttpHandler)
{
var foundFooHeader = false;
var fooheaderCount = 0;
var requests = mockHttpHandler.CapturedRequests;

requests.Should().NotBeEmpty("because there should be at least one request");
foreach (var request in requests) {
var requestHeaders = request.Headers.GetValues ("foo");
foundFooHeader = false;
foreach (var requestHeader in requestHeaders) {
foundFooHeader = true;
Assert.AreEqual ("bar", requestHeader);
try {
var requestHeaders = request.Headers.GetValues("foo");
foreach(var requestHeader in requestHeaders) {
fooheaderCount++;
requestHeader.Should().Be("bar", "because otherwise the custom header is incorrect");
}
} catch(InvalidOperationException) {
Assert.Fail("No custom header found");
}
}
Assert.IsTrue (foundFooHeader);

fooheaderCount.Should().Be(requests.Count, "because every request should have the custom header");
}

/// <exception cref="System.Exception"></exception>
Expand Down

0 comments on commit 16af81f

Please sign in to comment.