protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var rq = client.Open(new Java.Net.URL(request.RequestUri.ToString()));

            rq.RequestMethod = request.Method.Method.ToUpperInvariant();

            foreach (var kvp in request.Headers)
            {
                rq.SetRequestProperty(kvp.Key, kvp.Value.FirstOrDefault());
            }

            if (request.Content != null)
            {
                foreach (var kvp in request.Content.Headers)
                {
                    rq.SetRequestProperty(kvp.Key, kvp.Value.FirstOrDefault());
                }

                var contentStream = await Task.Run(async() => await request.Content.ReadAsStreamAsync()).ConfigureAwait(false);
                await copyToAsync(contentStream, rq.OutputStream, cancellationToken).ConfigureAwait(false);

                rq.OutputStream.Close();
            }

            return(await Task.Run(() => {
                if (cancellationToken.IsCancellationRequested)
                {
                    throw new TaskCanceledException();
                }

                // NB: This is the line that blocks until we have headers
                var ret = new HttpResponseMessage((HttpStatusCode)rq.ResponseCode);

                if (cancellationToken.IsCancellationRequested)
                {
                    throw new TaskCanceledException();
                }

                ret.Content = new StreamContent(new ConcatenatingStream(new Func <Stream>[] {
                    () => rq.InputStream,
                    () => rq.ErrorStream ?? new MemoryStream(),
                }, true));

                cancellationToken.Register(ret.Content.Dispose);

                ret.RequestMessage = request;
                return ret;
            }));
        }
        protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var java_uri = request.RequestUri.GetComponents(UriComponents.AbsoluteUri, UriFormat.UriEscaped);
            var url      = new Java.Net.URL(java_uri);

            Java.Net.HttpURLConnection rq;
            try {
                rq = client.Open(url);
            } catch (Java.Net.UnknownHostException e) {
                throw new WebException("Name resolution failure", e, WebExceptionStatus.NameResolutionFailure, null);
            }
            rq.RequestMethod = request.Method.Method.ToUpperInvariant();

            foreach (var kvp in request.Headers)
            {
                rq.SetRequestProperty(kvp.Key, kvp.Value.FirstOrDefault());
            }

            if (request.Content != null)
            {
                foreach (var kvp in request.Content.Headers)
                {
                    rq.SetRequestProperty(kvp.Key, kvp.Value.FirstOrDefault());
                }

                await Task.Run(async() => {
                    var contentStream = await request.Content.ReadAsStreamAsync().ConfigureAwait(false);
                    await copyToAsync(contentStream, rq.OutputStream, cancellationToken).ConfigureAwait(false);
                }, cancellationToken).ConfigureAwait(false);

                rq.OutputStream.Close();
            }

            return(await Task.Run(() => {
                // NB: This is the line that blocks until we have headers
                var ret = new HttpResponseMessage((HttpStatusCode)rq.ResponseCode);

                // Test to see if we're being redirected (i.e. in a captive network)
                if (throwOnCaptiveNetwork && (url.Host != rq.URL.Host))
                {
                    throw new WebException("Hostnames don't match, you are probably on a captive network");
                }

                cancellationToken.ThrowIfCancellationRequested();

                ret.Content = new StreamContent(new ConcatenatingStream(new Func <Stream>[] {
                    () => ret.IsSuccessStatusCode ? rq.InputStream : new MemoryStream(),
                    () => rq.ErrorStream ?? new MemoryStream(),
                }, true));

                var keyValuePairs = rq.HeaderFields.Keys
                                    .Where(k => k != null) // Yes, this happens. I can't even.
                                    .SelectMany(k => rq.HeaderFields[k]
                                                .Select(val => new { Key = k, Value = val }));

                foreach (var v in keyValuePairs)
                {
                    ret.Headers.TryAddWithoutValidation(v.Key, v.Value);
                    ret.Content.Headers.TryAddWithoutValidation(v.Key, v.Value);
                }

                cancellationToken.Register(ret.Content.Dispose);

                ret.RequestMessage = request;
                return ret;
            }, cancellationToken).ConfigureAwait(false));
        }