// Convenience method for testing
        internal static IDictionary <string, object> ReadToDatabase(IEnumerable <byte> data, IDictionary <string, string> headers,
                                                                    Database db)
        {
            var realized = data.ToArray();

            if (realized.Length == 0)
            {
                throw new CouchbaseLiteException(StatusCode.BadJson);
            }

            var reader = new MultipartDocumentReader(db);

            reader.SetHeaders(headers);
            reader.AppendData(data);
            reader.Finish();

            return(reader.document);
        }
예제 #2
0
        internal void SendAsyncMultipartDownloaderRequest(HttpMethod method, string relativePath, object body, Database db, RemoteRequestCompletionBlock onCompletion)
        {
            try {
                var urlStr = BuildRelativeURLString(relativePath);
                var url = new Uri(urlStr);

                var message = new HttpRequestMessage(method, url);
                message.Headers.Add("Accept", "*/*");
                AddRequestHeaders(message);

                var client = clientFactory.GetHttpClient(false);
                var challengeResponseAuth = Authenticator as IChallengeResponseAuthenticator;
                if (challengeResponseAuth != null) {
                    var authHandler = clientFactory.Handler as DefaultAuthHandler;
                    if (authHandler != null) {
                        authHandler.Authenticator = challengeResponseAuth;
                    }

                    challengeResponseAuth.PrepareWithRequest(message);
                }

                var authHeader = AuthUtils.GetAuthenticationHeaderValue(Authenticator, message.RequestUri);
                if (authHeader != null) {
                    client.DefaultRequestHeaders.Authorization = authHeader;
                }

                client.SendAsync(message, CancellationTokenSource.Token).ContinueWith(new Action<Task<HttpResponseMessage>>(responseMessage =>
                {
                    object fullBody = null;
                    Exception error = null;
                    try {
                        var response = responseMessage.Result;
                        // add in cookies to global store
                        //CouchbaseLiteHttpClientFactory.Instance.AddCookies(clientFactory.HttpHandler.CookieContainer.GetCookies(url));

                        var status = response.StatusCode;
                        if ((Int32)status.GetStatusCode() >= 300) {
                            Log.E(TAG, "Got error " + Sharpen.Extensions.ToString(status.GetStatusCode()));
                            Log.E(TAG, "Request was for: " + message);
                            Log.E(TAG, "Status reason: " + response.ReasonPhrase);
                            error = new WebException(response.ReasonPhrase);
                        } else {
                            var entity = response.Content;
                            var contentTypeHeader = response.Content.Headers.ContentType;
                            InputStream inputStream = null;
                            if (contentTypeHeader != null && contentTypeHeader.ToString().Contains("multipart/related")) {
                                try {
                                    var reader = new MultipartDocumentReader(LocalDatabase);
                                    var contentType = contentTypeHeader.ToString();
                                    reader.SetContentType(contentType);

                                    var inputStreamTask = entity.ReadAsStreamAsync();
                                    //inputStreamTask.Wait(90000, CancellationTokenSource.Token);
                                    inputStream = inputStreamTask.Result;

                                    const int bufLen = 1024;
                                    var buffer = new byte[bufLen];

                                    int numBytesRead = 0;
                                    while ((numBytesRead = inputStream.Read(buffer)) != -1) {
                                        if (numBytesRead != bufLen) {
                                            var bufferToAppend = new Couchbase.Lite.Util.ArraySegment<Byte>(buffer, 0, numBytesRead);
                                            reader.AppendData(bufferToAppend);
                                        } else {
                                            reader.AppendData(buffer);
                                        }
                                    }

                                    reader.Finish();
                                    fullBody = reader.GetDocumentProperties();

                                    if (onCompletion != null) {
                                        onCompletion(fullBody, error);
                                    }
                                } catch (Exception ex) {
                                    Log.E(TAG, "SendAsyncMultipartDownloaderRequest has an error occurred.", ex);
                                } finally {
                                    try {
                                        inputStream.Close();
                                    } catch (Exception) { }
                                }
                            } else {
                                if (entity != null) {
                                    try {
                                        var readTask = entity.ReadAsStreamAsync();
                                        //readTask.Wait(); // TODO: This should be scaled based on content length.
                                        inputStream = readTask.Result;
                                        fullBody = Manager.GetObjectMapper().ReadValue<Object>(inputStream);
                                        if (onCompletion != null)
                                            onCompletion(fullBody, error);
                                    } catch (Exception ex) {
                                        Log.E(TAG, "SendAsyncMultipartDownloaderRequest has an error occurred.", ex);
                                    } finally {
                                        try {
                                            inputStream.Close();
                                        } catch (Exception) { }
                                    }
                                }
                            }
                        }
                    } catch (System.Net.ProtocolViolationException e) {
                        Log.E(TAG, "client protocol exception", e);
                        error = e;
                    } catch (IOException e) {
                        Log.E(TAG, "IO Exception", e);
                        error = e;
                    } finally {
                        client.Dispose();
                    }
                }), WorkExecutor.Scheduler);
            } catch (UriFormatException e) {
                Log.E(TAG, "Malformed URL for async request", e);
            }
        }
 /// <summary>This method is called when a part is complete.</summary>
 /// <remarks>This method is called when a part is complete.</remarks>
 public virtual void FinishedPart()
 {
     Log.V(Tag, "{0}: Finished document".Fmt(this));
     if (_docReader == null)
     {
         throw new InvalidOperationException("_docReader is not defined");
     }
     _docReader.Finish();
     ++_docCount;
     OnDocumentDownloaded(_docReader.GetDocumentProperties());
     _docReader = null;
 }
 /// <summary>This method is called when a part's headers have been parsed, before its data is parsed.
 ///     </summary>
 /// <remarks>This method is called when a part's headers have been parsed, before its data is parsed.
 ///     </remarks>
 public void StartedPart(IDictionary<string, string> headers)
 {
     if (_docReader != null)
     {
         throw new InvalidOperationException("_docReader is already defined");
     }
     Log.V(Tag, "{0}: Starting new document; headers ={1}", this, headers);
     Log.V(Tag, "{0}: Starting new document; ID={1}".Fmt(this, headers.Get("X-Doc-Id")));
     _docReader = new MultipartDocumentReader(db);
     _docReader.SetContentType(headers.Get ("Content-Type"));
     _docReader.StartedPart(headers);
 }
        // Factors out the logic of opening the database and reading the document body from the HTTP request
        // and performs the specified logic on the body received in the request, barring any problems
        private static CouchbaseLiteResponse PerformLogicWithDocumentBody(ICouchbaseListenerContext context, 
            Func<Database, Body, CouchbaseLiteResponse> callback)
        {
            return DatabaseMethods.PerformLogicWithDatabase(context, true, db =>
            {
                MultipartDocumentReader reader = new MultipartDocumentReader(db);
                reader.SetContentType(context.RequestHeaders["Content-Type"]);
                reader.AppendData(context.BodyStream.ReadAllBytes());
                try {
                    reader.Finish();
                } catch(InvalidOperationException) {
                    return context.CreateResponse(StatusCode.BadRequest);
                }

                return callback(db, new Body(reader.GetDocumentProperties()));
            });
        }
        public static IDictionary<string, object> ReadToDatabase(IEnumerable<byte> data, IDictionary<string, string> headers, 
            Database db)
        {
            var realized = data.ToArray();
            if (realized.Length == 0) {
                throw new CouchbaseLiteException(StatusCode.BadJson);
            }

            var reader = new MultipartDocumentReader(db);
            reader.SetHeaders(headers);
            reader.AppendData(data);
            reader.Finish();

            return reader.document;
        }
        protected internal override void ExecuteRequest(HttpClient httpClient, HttpRequestMessage
                                                        request)
        {
            object       fullBody = null;
            Exception    error    = null;
            HttpResponse response = null;

            try
            {
                if (request.IsAborted())
                {
                    RespondWithResult(fullBody, new Exception(string.Format("%s: Request %s has been aborted"
                                                                            , this, request)), response);
                    return;
                }
                response = httpClient.Execute(request);
                try
                {
                    // add in cookies to global store
                    if (httpClient is DefaultHttpClient)
                    {
                        DefaultHttpClient defaultHttpClient = (DefaultHttpClient)httpClient;
                        this.clientFactory.AddCookies(defaultHttpClient.GetCookieStore().GetCookies());
                    }
                }
                catch (Exception e)
                {
                    Log.E(Log.TagRemoteRequest, "Unable to add in cookies to global store", e);
                }
                StatusLine status = response.GetStatusLine();
                if (status.GetStatusCode() >= 300)
                {
                    Log.E(Log.TagRemoteRequest, "Got error status: %d for %s.  Reason: %s", status.GetStatusCode
                              (), request, status.GetReasonPhrase());
                    error = new HttpResponseException(status.GetStatusCode(), status.GetReasonPhrase(
                                                          ));
                }
                else
                {
                    HttpEntity  entity            = response.GetEntity();
                    Header      contentTypeHeader = entity.GetContentType();
                    InputStream inputStream       = null;
                    if (contentTypeHeader != null && contentTypeHeader.GetValue().Contains("multipart/related"
                                                                                           ))
                    {
                        try
                        {
                            MultipartDocumentReader reader = new MultipartDocumentReader(response, db);
                            reader.SetContentType(contentTypeHeader.GetValue());
                            inputStream = entity.GetContent();
                            int    bufLen       = 1024;
                            byte[] buffer       = new byte[bufLen];
                            int    numBytesRead = 0;
                            while ((numBytesRead = inputStream.Read(buffer)) != -1)
                            {
                                if (numBytesRead != bufLen)
                                {
                                    byte[] bufferToAppend = Arrays.CopyOfRange(buffer, 0, numBytesRead);
                                    reader.AppendData(bufferToAppend);
                                }
                                else
                                {
                                    reader.AppendData(buffer);
                                }
                            }
                            reader.Finish();
                            fullBody = reader.GetDocumentProperties();
                            RespondWithResult(fullBody, error, response);
                        }
                        finally
                        {
                            try
                            {
                                inputStream.Close();
                            }
                            catch (IOException)
                            {
                            }
                        }
                    }
                    else
                    {
                        if (entity != null)
                        {
                            try
                            {
                                inputStream = entity.GetContent();
                                fullBody    = Manager.GetObjectMapper().ReadValue <object>(inputStream);
                                RespondWithResult(fullBody, error, response);
                            }
                            finally
                            {
                                try
                                {
                                    inputStream.Close();
                                }
                                catch (IOException)
                                {
                                }
                            }
                        }
                    }
                }
            }
            catch (IOException e)
            {
                Log.E(Log.TagRemoteRequest, "%s: io exception", e, this);
                error = e;
                RespondWithResult(fullBody, e, response);
            }
            catch (Exception e)
            {
                Log.E(Log.TagRemoteRequest, "%s: executeRequest() Exception: ", e, this);
                error = e;
                RespondWithResult(fullBody, e, response);
            }
            finally
            {
                Log.E(Log.TagRemoteRequest, "%s: executeRequest() finally", this);
            }
        }
        protected internal override void ExecuteRequest(HttpClient httpClient, HttpRequestMessage
                                                        request)
        {
            object    fullBody = null;
            Exception error    = null;

            try
            {
                HttpResponse response = httpClient.Execute(request);
                try
                {
                    // add in cookies to global store
                    if (httpClient is DefaultHttpClient)
                    {
                        DefaultHttpClient defaultHttpClient = (DefaultHttpClient)httpClient;
                        CouchbaseLiteHttpClientFactory.Instance.AddCookies(defaultHttpClient.GetCookieStore
                                                                               ().GetCookies());
                    }
                }
                catch (Exception e)
                {
                    Log.E(Database.Tag, "Unable to add in cookies to global store", e);
                }
                StatusLine status = response.GetStatusLine();
                if (status.GetStatusCode() >= 300)
                {
                    Log.E(Database.Tag, "Got error " + Sharpen.Extensions.ToString(status.GetStatusCode
                                                                                       ()));
                    Log.E(Database.Tag, "Request was for: " + request.ToString());
                    Log.E(Database.Tag, "Status reason: " + status.GetReasonPhrase());
                    error = new HttpResponseException(status.GetStatusCode(), status.GetReasonPhrase(
                                                          ));
                }
                else
                {
                    HttpEntity  entity            = response.GetEntity();
                    Header      contentTypeHeader = entity.GetContentType();
                    InputStream inputStream       = null;
                    if (contentTypeHeader != null && contentTypeHeader.GetValue().Contains("multipart/related"
                                                                                           ))
                    {
                        try
                        {
                            MultipartDocumentReader reader = new MultipartDocumentReader(response, db);
                            reader.SetContentType(contentTypeHeader.GetValue());
                            inputStream = entity.GetContent();
                            int    bufLen       = 1024;
                            byte[] buffer       = new byte[bufLen];
                            int    numBytesRead = 0;
                            while ((numBytesRead = inputStream.Read(buffer)) != -1)
                            {
                                if (numBytesRead != bufLen)
                                {
                                    byte[] bufferToAppend = Arrays.CopyOfRange(buffer, 0, numBytesRead);
                                    reader.AppendData(bufferToAppend);
                                }
                                else
                                {
                                    reader.AppendData(buffer);
                                }
                            }
                            reader.Finish();
                            fullBody = reader.GetDocumentProperties();
                            RespondWithResult(fullBody, error);
                        }
                        finally
                        {
                            try
                            {
                                inputStream.Close();
                            }
                            catch (IOException)
                            {
                            }
                        }
                    }
                    else
                    {
                        if (entity != null)
                        {
                            try
                            {
                                inputStream = entity.GetContent();
                                fullBody    = Manager.GetObjectMapper().ReadValue <object>(inputStream);
                                RespondWithResult(fullBody, error);
                            }
                            finally
                            {
                                try
                                {
                                    inputStream.Close();
                                }
                                catch (IOException)
                                {
                                }
                            }
                        }
                    }
                }
            }
            catch (ClientProtocolException e)
            {
                Log.E(Database.Tag, "client protocol exception", e);
                error = e;
            }
            catch (IOException e)
            {
                Log.E(Database.Tag, "io exception", e);
                error = e;
            }
        }
 protected internal override void ExecuteRequest(HttpClient httpClient, HttpRequestMessage
      request)
 {
     object fullBody = null;
     Exception error = null;
     HttpResponse response = null;
     try
     {
         if (request.IsAborted())
         {
             RespondWithResult(fullBody, new Exception(string.Format("%s: Request %s has been aborted"
                 , this, request)), response);
             return;
         }
         response = httpClient.Execute(request);
         try
         {
             // add in cookies to global store
             if (httpClient is DefaultHttpClient)
             {
                 DefaultHttpClient defaultHttpClient = (DefaultHttpClient)httpClient;
                 this.clientFactory.AddCookies(defaultHttpClient.GetCookieStore().GetCookies());
             }
         }
         catch (Exception e)
         {
             Log.E(Log.TagRemoteRequest, "Unable to add in cookies to global store", e);
         }
         StatusLine status = response.GetStatusLine();
         if (status.GetStatusCode() >= 300)
         {
             Log.E(Log.TagRemoteRequest, "Got error status: %d for %s.  Reason: %s", status.GetStatusCode
                 (), request, status.GetReasonPhrase());
             error = new HttpResponseException(status.GetStatusCode(), status.GetReasonPhrase(
                 ));
         }
         else
         {
             HttpEntity entity = response.GetEntity();
             Header contentTypeHeader = entity.GetContentType();
             InputStream inputStream = null;
             if (contentTypeHeader != null && contentTypeHeader.GetValue().Contains("multipart/related"
                 ))
             {
                 try
                 {
                     MultipartDocumentReader reader = new MultipartDocumentReader(response, db);
                     reader.SetContentType(contentTypeHeader.GetValue());
                     inputStream = entity.GetContent();
                     int bufLen = 1024;
                     byte[] buffer = new byte[bufLen];
                     int numBytesRead = 0;
                     while ((numBytesRead = inputStream.Read(buffer)) != -1)
                     {
                         if (numBytesRead != bufLen)
                         {
                             byte[] bufferToAppend = Arrays.CopyOfRange(buffer, 0, numBytesRead);
                             reader.AppendData(bufferToAppend);
                         }
                         else
                         {
                             reader.AppendData(buffer);
                         }
                     }
                     reader.Finish();
                     fullBody = reader.GetDocumentProperties();
                     RespondWithResult(fullBody, error, response);
                 }
                 finally
                 {
                     try
                     {
                         inputStream.Close();
                     }
                     catch (IOException)
                     {
                     }
                 }
             }
             else
             {
                 if (entity != null)
                 {
                     try
                     {
                         inputStream = entity.GetContent();
                         fullBody = Manager.GetObjectMapper().ReadValue<object>(inputStream);
                         RespondWithResult(fullBody, error, response);
                     }
                     finally
                     {
                         try
                         {
                             inputStream.Close();
                         }
                         catch (IOException)
                         {
                         }
                     }
                 }
             }
         }
     }
     catch (IOException e)
     {
         Log.E(Log.TagRemoteRequest, "%s: io exception", e, this);
         error = e;
         RespondWithResult(fullBody, e, response);
     }
     catch (Exception e)
     {
         Log.E(Log.TagRemoteRequest, "%s: executeRequest() Exception: ", e, this);
         error = e;
         RespondWithResult(fullBody, e, response);
     }
     finally
     {
         Log.E(Log.TagRemoteRequest, "%s: executeRequest() finally", this);
     }
 }
        internal void SendAsyncMultipartDownloaderRequest(HttpMethod method, string relativePath, object body, Database db, RemoteRequestCompletionBlock onCompletion)
        {
            try {
                var url = _baseUrl.Append(relativePath);

                var message = new HttpRequestMessage(method, url);
                message.Headers.Add("Accept", "*/*");
                AddRequestHeaders(message);

                var client = default(CouchbaseLiteHttpClient);
                if(!_client.AcquireFor(TimeSpan.FromSeconds(1), out client)) {
                    Log.To.Sync.I(Tag, "Client is disposed, aborting request to {0}", new SecureLogString(relativePath, LogMessageSensitivity.PotentiallyInsecure));
                    return;
                }

                client.Authenticator = Authenticator;
                var request = client.SendAsync(message, _cancellationTokenSource.Token).ContinueWith(new Action<Task<HttpResponseMessage>>(responseMessage =>
                {
                    object fullBody = null;
                    Exception error = null;
                    try {
                        if(responseMessage.IsFaulted) {
                            error = responseMessage.Exception.InnerException;
                            if(onCompletion != null) {
                                onCompletion(null, error);
                            }

                            return;
                        }

                        var response = responseMessage.Result;
                        // add in cookies to global store
                        //CouchbaseLiteHttpClientFactory.Instance.AddCoIokies(clientFactory.HttpHandler.CookieContainer.GetCookies(url));

                        var status = response.StatusCode;
                        if((Int32)status.GetStatusCode() >= 300) {
                            Log.To.Sync.W(Tag, "Got error {0}", status.GetStatusCode());
                            Log.To.Sync.W(Tag, "Request was for: " + message);
                            Log.To.Sync.W(Tag, "Status reason: " + response.ReasonPhrase);
                            Log.To.Sync.W(Tag, "Passing error onto callback...");
                            error = new HttpResponseException(status);
                            if(onCompletion != null) {
                                onCompletion(null, error);
                            }
                        } else {
                            var entity = response.Content;
                            var contentTypeHeader = response.Content.Headers.ContentType;
                            Stream inputStream = null;
                            if(contentTypeHeader != null && contentTypeHeader.ToString().Contains("multipart/related")) {
                                try {
                                    var reader = new MultipartDocumentReader(db);
                                    var contentType = contentTypeHeader.ToString();
                                    reader.SetContentType(contentType);

                                    var inputStreamTask = entity.ReadAsStreamAsync();
                                    //inputStreamTask.Wait(90000, CancellationTokenSource.Token);
                                    inputStream = inputStreamTask.Result;

                                    const int bufLen = 1024;
                                    var buffer = new byte[bufLen];

                                    int numBytesRead = 0;
                                    while((numBytesRead = inputStream.Read(buffer, 0, buffer.Length)) > 0) {
                                        if(numBytesRead != bufLen) {
                                            var bufferToAppend = new Couchbase.Lite.Util.ArraySegment<Byte>(buffer, 0, numBytesRead);
                                            reader.AppendData(bufferToAppend);
                                        } else {
                                            reader.AppendData(buffer);
                                        }
                                    }

                                    reader.Finish();
                                    fullBody = reader.GetDocumentProperties();

                                    if(onCompletion != null) {
                                        onCompletion(fullBody, error);
                                    }
                                } catch(Exception ex) {
                                    Log.To.Sync.W(Tag, "SendAsyncMultipartDownloaderRequest got an exception, aborting...", ex);
                                } finally {
                                    try {
                                        inputStream.Close();
                                    } catch(Exception) { }
                                }
                            } else {
                                if(entity != null) {
                                    try {
                                        var readTask = entity.ReadAsStreamAsync();
                                        //readTask.Wait(); // TODO: This should be scaled based on content length.
                                        inputStream = readTask.Result;
                                        fullBody = Manager.GetObjectMapper().ReadValue<Object>(inputStream);
                                        if(onCompletion != null)
                                            onCompletion(fullBody, error);
                                    } catch(Exception ex) {
                                        Log.To.Sync.W(Tag, "SendAsyncMultipartDownloaderRequest got an exception, aborting...", ex);
                                    } finally {
                                        try {
                                            inputStream.Close();
                                        } catch(Exception) { }
                                    }
                                }
                            }
                        }
                    } catch(Exception e) {
                        Log.To.Sync.W(Tag, "Got exception during SendAsyncMultipartDownload, aborting...");
                        error = e;
                    } finally {
                        Task dummy;
                        _requests.TryRemove(message, out dummy);
                        responseMessage.Result.Dispose();
                    }
                }), _workExecutor.Scheduler);
                _requests.TryAdd(message, request);
            } catch(UriFormatException e) {
                Log.To.Sync.W(Tag, "Malformed URL for async request, aborting...", e);
            }
        }
예제 #11
0
        internal void SendAsyncMultipartDownloaderRequest(HttpMethod method, string relativePath, object body, Database db, RemoteRequestCompletionBlock onCompletion)
        {
            try
            {
                var urlStr = BuildRelativeURLString(relativePath);
                var url = new Uri(urlStr);

                var message = new HttpRequestMessage(method, url);
                message.Headers.Add("Accept", "*/*");
                AddRequestHeaders(message);

                var httpClient = clientFactory.GetHttpClient();
                httpClient.SendAsync(message, HttpCompletionOption.ResponseHeadersRead, CancellationTokenSource.Token)
                    .ContinueWith(new Action<Task<HttpResponseMessage>>(responseMessage=> {
                        object fullBody = null;
                        Exception error = null;
                        try
                        {
                            var response = responseMessage.Result;
                            // add in cookies to global store
							CouchbaseLiteHttpClientFactory.Instance.AddCookies(clientFactory.HttpHandler.CookieContainer.GetCookies(url), url);
                               
                            var status = response.StatusCode;
                            if ((Int32)status.GetStatusCode() >= 300)
                            {
                                Log.E(Database.Tag, "Got error " + Sharpen.Extensions.ToString(status.GetStatusCode
                                    ()));
                                Log.E(Database.Tag, "Request was for: " + message);
                                Log.E(Database.Tag, "Status reason: " + response.ReasonPhrase);
								error = new HttpResponseException(status); //, response.ReasonPhrase);
                            }
                        else
                        {
                            var entity = response.Content;
                            var contentTypeHeader = response.Content.Headers.ContentType;
                            InputStream inputStream = null;
                            if (contentTypeHeader != null && contentTypeHeader.ToString().Contains("multipart/related"))
                            {
                                try
                                {
                                    var reader = new MultipartDocumentReader(responseMessage.Result, LocalDatabase);
                                    reader.SetContentType(contentTypeHeader.MediaType);

                                    var inputStreamTask = entity.ReadAsStreamAsync();
                                    inputStreamTask.Wait(90000, CancellationTokenSource.Token);
                                    
                                    const int bufLen = 1024;
                                    var buffer = new byte[bufLen];
                                    
                                    int numBytesRead = 0;
                                    while ((numBytesRead = inputStream.Read(buffer)) != -1)
                                    {
                                        if (numBytesRead != bufLen)
                                        {
                                            var bufferToAppend = new ArraySegment<Byte>(buffer, 0, numBytesRead).Array;
                                            reader.AppendData(bufferToAppend);
                                        }
                                        else
                                        {
                                            reader.AppendData(buffer);
                                        }
                                    }

                                    reader.Finish();
                                    fullBody = reader.GetDocumentProperties();

                                    if (onCompletion != null)
                                        onCompletion(fullBody, error);
                                }
                                finally
                                {
                                    try
                                    {
                                        inputStream.Close();
                                    }
                                    catch (IOException)
                                    {
                                            // NOTE: swallow?
                                    }
                                }
                            }
                            else
                            {
                                if (entity != null)
                                {
                                    try
                                    {
                                        var readTask = entity.ReadAsStreamAsync();
                                        readTask.Wait(); // TODO: This should be scaled based on content length.
                                        inputStream = readTask.Result;
                                        fullBody = Manager.GetObjectMapper().ReadValue<Object>(inputStream);
                                        if (onCompletion != null)
                                            onCompletion(fullBody, error);
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.E(Tag, ex.Message);
                                    }
                                    finally
                                    {
                                        try
                                        {
                                            inputStream.Close();
                                        }
                                        catch (IOException)
                                        {
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (ProtocolViolationException e)
                    {
                        Log.E(Database.Tag, "client protocol exception", e);
                        error = e;
                    }
                    catch (IOException e)
                    {
                        Log.E(Database.Tag, "io exception", e);
                        error = e;
                    }
                    }));
            }
			#if PORTABLE
			catch (FormatException e)
			#else
            catch (UriFormatException e)
			#endif
            {
                Log.E(Database.Tag, "Malformed URL for async request", e);
            }
        }
        // Factors out the logic of opening the database and reading the document body from the HTTP request
        // and performs the specified logic on the body received in the request, barring any problems
        private static CouchbaseLiteResponse PerformLogicWithDocumentBody(ICouchbaseListenerContext context, 
            Func<Database, Body, CouchbaseLiteResponse> callback)
        {
            return DatabaseMethods.PerformLogicWithDatabase(context, true, db =>
            {
                MultipartDocumentReader reader = new MultipartDocumentReader(db);
                reader.SetContentType(context.RequestHeaders["Content-Type"]);
                
                try {
                    reader.AppendData(context.BodyStream.ReadAllBytes());
                    reader.Finish();
                } catch(InvalidOperationException e) {
                    Log.To.Router.E(TAG, "Exception trying to read data from multipart upload", e);
                    return context.CreateResponse(StatusCode.BadRequest);
                } catch(IOException e) {
                    Log.To.Router.E(TAG, "IOException while reading context body", e);
                    return context.CreateResponse(StatusCode.RequestTimeout);
                }

                return callback(db, new Body(reader.GetDocumentProperties()));
            });
        }
        /// <summary>This method is called when a part is complete.</summary>
        /// <remarks>This method is called when a part is complete.</remarks>
        public virtual void FinishedPart()
        {
            if (_docReader == null) {
                Log.To.Sync.E(Tag, "FinishedPart called on a non-started object");
                throw new InvalidOperationException("FinishedPart called on a non-started object");
            }

            Log.To.Sync.V(Tag, "{0} Finished document", this);
            _docReader.Finish();
            ++_docCount;
            OnDocumentDownloaded(_docReader.GetDocumentProperties());
            _docReader = null;
        }
        /// <summary>This method is called when a part's headers have been parsed, before its data is parsed.
        ///     </summary>
        /// <remarks>This method is called when a part's headers have been parsed, before its data is parsed.
        ///     </remarks>
        public void StartedPart(IDictionary<string, string> headers)
        {
            if (_docReader != null) {
                Log.To.Sync.E(Tag, "StartedPart called on an already started object");
                throw new InvalidOperationException("StartedPart called on an already started object");
            }

            Log.To.Sync.V(Tag, "{0}: Starting new document; ID={1}", this, headers.Get("X-Doc-ID"));
            _docReader = new MultipartDocumentReader(_db);
            _docReader.SetContentType(headers.Get ("Content-Type"));
            _docReader.StartedPart(headers);
        }
		protected internal override void ExecuteRequest(HttpClient httpClient, HttpRequestMessage
			 request)
		{
			object fullBody = null;
			Exception error = null;
			try
			{
				HttpResponse response = httpClient.Execute(request);
				try
				{
					// add in cookies to global store
					if (httpClient is DefaultHttpClient)
					{
						DefaultHttpClient defaultHttpClient = (DefaultHttpClient)httpClient;
						CouchbaseLiteHttpClientFactory.Instance.AddCookies(defaultHttpClient.GetCookieStore
							().GetCookies());
					}
				}
				catch (Exception e)
				{
					Log.E(Database.Tag, "Unable to add in cookies to global store", e);
				}
				StatusLine status = response.GetStatusLine();
				if (status.GetStatusCode() >= 300)
				{
					Log.E(Database.Tag, "Got error " + Sharpen.Extensions.ToString(status.GetStatusCode
						()));
					Log.E(Database.Tag, "Request was for: " + request.ToString());
					Log.E(Database.Tag, "Status reason: " + status.GetReasonPhrase());
					error = new HttpResponseException(status.GetStatusCode(), status.GetReasonPhrase(
						));
				}
				else
				{
					HttpEntity entity = response.GetEntity();
					Header contentTypeHeader = entity.GetContentType();
					InputStream inputStream = null;
					if (contentTypeHeader != null && contentTypeHeader.GetValue().Contains("multipart/related"
						))
					{
						try
						{
							MultipartDocumentReader reader = new MultipartDocumentReader(response, db);
							reader.SetContentType(contentTypeHeader.GetValue());
							inputStream = entity.GetContent();
							int bufLen = 1024;
							byte[] buffer = new byte[bufLen];
							int numBytesRead = 0;
							while ((numBytesRead = inputStream.Read(buffer)) != -1)
							{
								if (numBytesRead != bufLen)
								{
									byte[] bufferToAppend = Arrays.CopyOfRange(buffer, 0, numBytesRead);
									reader.AppendData(bufferToAppend);
								}
								else
								{
									reader.AppendData(buffer);
								}
							}
							reader.Finish();
							fullBody = reader.GetDocumentProperties();
							RespondWithResult(fullBody, error);
						}
						finally
						{
							try
							{
								inputStream.Close();
							}
							catch (IOException)
							{
							}
						}
					}
					else
					{
						if (entity != null)
						{
							try
							{
								inputStream = entity.GetContent();
								fullBody = Manager.GetObjectMapper().ReadValue<object>(inputStream);
								RespondWithResult(fullBody, error);
							}
							finally
							{
								try
								{
									inputStream.Close();
								}
								catch (IOException)
								{
								}
							}
						}
					}
				}
			}
			catch (ClientProtocolException e)
			{
				Log.E(Database.Tag, "client protocol exception", e);
				error = e;
			}
			catch (IOException e)
			{
				Log.E(Database.Tag, "io exception", e);
				error = e;
			}
		}