Exemple #1
0
		// The requirements are:
		// * We must read at least one byte from the stream every time
		//   we get a HasBytesAvailable event.
		// * SerializeToStreamAsync is executed on a separate thread,
		//   so reads must somehow be synchronized with that thread.
		//
		// Current implementation:
		// * We read data in ReadStreamData (on the same thread
		//   we got the HasBytesAvailable event, i.e. inside the 
		//   HasBytesAvailable event handler).
		// * Data is stored in a class-level buffer.
		// * SerializeToStreamAsync blocks while waiting for
		//   data from ReadStreamData.
		// * ReadStreamData will only read more data once SerializeToStreamAsync
		//   has consumed any existing data. This means we'll be
		//   blocking in the HasBytesAvailable event handler until
		//   any previously read data has been processed (this prevents
		//   any unbound memory growth).

		public CFContentStream (CFHTTPStream stream)
		{
			this.http_stream = stream;
			data = new BufferData () {
				Buffer = new byte [4096],
			};
			data_event = new AutoResetEvent (false);
			data_read_event = new AutoResetEvent (true);
			data_mutex = new Mutex ();
		}
Exemple #2
0
 void CloseStream(CFHTTPStream stream)
 {
     lock (streamBuckets) {
         if (streamBuckets.TryGetValue(stream.Handle, out var bucket))
         {
             bucket.Close();
             streamBuckets.Remove(stream.Handle);
         }
     }
     stream.Close();
 }
Exemple #3
0
        // The requirements are:
        // * We must read at least one byte from the stream every time
        //   we get a HasBytesAvailable event.
        // * SerializeToStreamAsync is executed on a separate thread,
        //   so reads must somehow be synchronized with that thread.
        //
        // Current implementation:
        // * We read data in ReadStreamData (on the same thread
        //   we got the HasBytesAvailable event, i.e. inside the
        //   HasBytesAvailable event handler).
        // * Data is stored in a class-level buffer.
        // * SerializeToStreamAsync blocks while waiting for
        //   data from ReadStreamData.
        // * ReadStreamData will only read more data once SerializeToStreamAsync
        //   has consumed any existing data. This means we'll be
        //   blocking in the HasBytesAvailable event handler until
        //   any previously read data has been processed (this prevents
        //   any unbound memory growth).

        public CFContentStream(CFHTTPStream stream)
        {
            this.http_stream = stream;
            data             = new BufferData()
            {
                Buffer = new byte [4096],
            };
            data_event      = new AutoResetEvent(false);
            data_read_event = new AutoResetEvent(true);
            data_mutex      = new Mutex();
        }
Exemple #4
0
        void CloseStream(CFHTTPStream stream)
        {
            StreamBucket bucket;

            if (streamBuckets.TryGetValue(stream.Handle, out bucket))
            {
                bucket.Close();
                streamBuckets.Remove(stream.Handle);
            }

            stream.Close();
        }
 protected override void Dispose(bool disposing)
 {
     if (disposing)
     {
         OnCanceled();
         if (stream != null)
         {
             stream.Dispose();
             stream = null;
         }
         if (openCts != null)
         {
             openCts.Dispose();
             openCts = null;
         }
     }
     base.Dispose(disposing);
 }
Exemple #6
0
        internal async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken, bool isFirstRequest)
        {
            sentRequest = true;

            CFHTTPStream stream;

            using (var message = CreateWebRequestAsync(request))
            {
                if (request.Content != null)
                {
                    var data = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);

                    message.SetBody(data);
                }

                stream = CFHTTPStream.CreateForHTTPRequest(message);
            }

            if (useSystemProxy)
            {
                var proxies = CF.CFNetwork.GetSystemProxySettings();
                if (proxies.HTTPEnable)
                {
                    stream.SetProxy(proxies);
                }
            }

            if (!isFirstRequest && allowAutoRedirect)
            {
                stream.ShouldAutoredirect = allowAutoRedirect;
            }
            stream.HasBytesAvailableEvent += HandleHasBytesAvailableEvent;
            stream.ErrorEvent             += HandleErrorEvent;
            stream.ClosedEvent            += HandleClosedEvent;

            var response = new TaskCompletionSource <HttpResponseMessage> ();

            if (cancellationToken.IsCancellationRequested)
            {
                response.SetCanceled();
                return(await response.Task);
            }

            var bucket = new StreamBucket()
            {
                Request  = request,
                Response = response,
            };

            streamBuckets.Add(stream.Handle, bucket);

            //
            // Always schedule stream events handling on main-loop. Due to ConfigureAwait (false) we may end up
            // on any thread-pool thread which may not have run-loop running
            //
            stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.ModeCommon);

            stream.Open();

            bucket.CancellationTokenRegistration = cancellationToken.Register(() => {
                StreamBucket bucket2;
                if (!streamBuckets.TryGetValue(stream.Handle, out bucket2))
                {
                    return;
                }

                bucket2.Response.TrySetCanceled();
                CloseStream(stream);
            });

            if (isFirstRequest)
            {
                var initialRequest = await response.Task;
                var status         = initialRequest.StatusCode;
                if (IsRedirect(status) && allowAutoRedirect)
                {
                    bucket.StreamCanBeDisposed = true;
                    // we do not care about the first stream cbs
                    stream.HasBytesAvailableEvent -= HandleHasBytesAvailableEvent;
                    stream.ErrorEvent             -= HandleErrorEvent;
                    stream.ClosedEvent            -= HandleClosedEvent;
                    // remove headers in a redirect for Authentication.
                    request.Headers.Authorization = null;
                    return(await SendAsync(request, cancellationToken, false).ConfigureAwait(false));
                }
                return(initialRequest);
            }
            return(await response.Task);
        }
 WebResponseStream(CFHTTPStream stream, WebRequestStream body)
 {
     this.stream = stream;
     this.body   = body;
     syncRoot    = new object();
 }
		void CloseStream (CFHTTPStream stream)
		{
			StreamBucket bucket;
			if (streamBuckets.TryGetValue (stream.Handle, out bucket)) {
				bucket.Close ();
				streamBuckets.Remove (stream.Handle);
			}

			stream.Close ();
		}
Exemple #9
0
        protected internal override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            sentRequest = true;

            CFHTTPStream stream;

            using (var message = CreateWebRequestAsync(request))
            {
                if (request.Content != null)
                {
                    var data = await request.Content.ReadAsByteArrayAsync().ConfigureAwait(false);

                    message.SetBody(data);
                }

                stream = CFHTTPStream.CreateForHTTPRequest(message);
            }

            if (useSystemProxy)
            {
                var proxies = CF.CFNetwork.GetSystemProxySettings();
                if (proxies.HTTPEnable)
                {
                    stream.SetProxy(proxies);
                }
            }

            stream.ShouldAutoredirect      = allowAutoRedirect;
            stream.HasBytesAvailableEvent += HandleHasBytesAvailableEvent;
            stream.ErrorEvent             += HandleErrorEvent;
            stream.ClosedEvent            += HandleClosedEvent;

            var response = new TaskCompletionSource <HttpResponseMessage> ();

            if (cancellationToken.IsCancellationRequested)
            {
                response.SetCanceled();
                return(await response.Task);
            }

            var bucket = new StreamBucket()
            {
                Request  = request,
                Response = response,
            };

            streamBuckets.Add(stream.Handle, bucket);

            //
            // Always schedule stream events handling on main-loop. Due to ConfigureAwait (false) we may end up
            // on any thread-pool thread which may not have run-loop running
            //
#if XAMCORE_2_0
            stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.ModeCommon);
#else
            stream.EnableEvents(CF.CFRunLoop.Main, CF.CFRunLoop.CFRunLoopCommonModes);
#endif

            stream.Open();

            bucket.CancellationTokenRegistration = cancellationToken.Register(() => {
                StreamBucket bucket2;
                if (!streamBuckets.TryGetValue(stream.Handle, out bucket2))
                {
                    return;
                }

                bucket2.Response.TrySetCanceled();
                CloseStream(stream);
            });

            return(await response.Task);
        }