Пример #1
0
        /// <devdoc>
        /// <para>Gets a <see cref='System.IO.Stream'/> that the application can use to write request data.
        ///    This property returns a stream that the calling application can write on.
        ///    This property is not settable.  Getting this property may cause the
        ///    request to be sent, if it wasn't already. Getting this property after
        ///    a request has been sent that doesn't have an entity body causes an
        ///    exception to be thrown.
        ///</para>
        /// </devdoc>
        public Stream GetRequestStream(out TransportContext context) {
#if DEBUG
            using (GlobalLog.SetThreadKind(ThreadKinds.User | ThreadKinds.Sync)) {
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream");
            if(Logging.On)Logging.Enter(Logging.Web, this, "GetRequestStream", "");

            context = null;

            CheckProtocol(true);

            // See if we're already submitted a request and have a result cached.
            if (_WriteAResult == null || !_WriteAResult.InternalPeekCompleted)
            {
                lock(this)
                {
                    if (_WriteAResult != null)
                    {
                        throw new InvalidOperationException(SR.GetString(SR.net_repcall));
                    }

                    // See if we're already submitted a request (e.g. via GetResponse).
                    if (SetRequestSubmitted())
                    {
                        // Not completed write stream, this is an application error.
                        throw new InvalidOperationException(SR.GetString(SR.net_reqsubmitted));
                    }

                    // If there's already been a _ReadAResult completed, it better have been with an exception, like an abort.
                    // We need to check within this lock.  Before the lock, _WriteAResult didn't exist so won't have been notified.
                    // BeginSubmitRequest() will fail silently if we go ahead and call it after an abort.  Since we know this is the
                    // first call to any of the [Begin]GetRe... methods by the above checks, we know ProcessResponse can't have been
                    // called or any other valid _ReadAResult created yet.
                    if (_ReadAResult != null)
                    {
                        GlobalLog.Assert(_ReadAResult.InternalPeekCompleted, "HttpWebRequest#{0}::GetRequestStream()|Incomplete _ReadAResult present on request.", ValidationHelper.HashString(this));
                        GlobalLog.Assert(_ReadAResult.Result is Exception, "HttpWebRequest#{0}::GetRequestStream()|_ReadAResult with successful completion already present on request.", ValidationHelper.HashString(this));
                        throw (Exception) _ReadAResult.Result;
                    }

                    // use the AsyncResult to return our Stream
                    _WriteAResult = new LazyAsyncResult(this, null, null);

                    Async = false;
                }

                // OK, we haven't submitted the request yet, so do so now
                // save off verb from origin Verb
                GlobalLog.Print("HttpWebRequest#" + ValidationHelper.HashString(this) + "GetRequestStream() resetting CurrentMethod to " + _OriginVerb);
                CurrentMethod = _OriginVerb;

                // Submit the Request, causes us to queue ourselves to a Connection and may block
                // It has happened that [....] path uses this loop the Retry memeber for handling resubmissions.
                while (m_Retry && !_WriteAResult.InternalPeekCompleted) {
                    _OldSubmitWriteStream = null;
                    _SubmitWriteStream = null;
                    BeginSubmitRequest();
                }

                while(Aborted && !_WriteAResult.InternalPeekCompleted)
                {
                    // spin untill the _CoreResponse is set
                    if (!(_CoreResponse is Exception))
                        Thread.SpinWait(1);
                    else
                        CheckWriteSideResponseProcessing();
                }
            }

            ConnectStream connectStream = _WriteAResult.InternalWaitForCompletion() as ConnectStream;
            _WriteAResult.EndCalled = true;
            if (connectStream == null)
            {
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetRequestStream", _WriteAResult.Result as Exception);
                throw (Exception) _WriteAResult.Result;
            }

            context = new ConnectStreamContext(connectStream);

            if(Logging.On)Logging.Exit(Logging.Web, this, "GetRequestStream", connectStream);
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::GetRequestStream", ValidationHelper.HashString(connectStream));
            return connectStream;
#if DEBUG
            }
#endif
        }
Пример #2
0
        /*
            RequestSubmitDone - Handle submit done callback.

            This is our submit done handler, called by the underlying connection
            code when a stream is available for our use. We save the stream for
            later use and signal the wait event.

            We also handle the continuation/termination of a BeginGetRequestStream,
            by saving out the result and calling its callback if needed.

            Input:  SubmitStream        - The stream we may write on.
                    Status              - The status of the submission.

            Returns: Nothing.

        */
        internal void SetRequestSubmitDone(ConnectStream submitStream) {
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone", ValidationHelper.HashString(submitStream));
            GlobalLog.ThreadContract(ThreadKinds.Unknown, "HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");

            if (!Async) {
                ConnectionAsyncResult.InvokeCallback();
            }

            if (AllowWriteStreamBuffering) {
                submitStream.EnableWriteBuffering();
            }

            if (submitStream.CanTimeout) {
                submitStream.ReadTimeout = ReadWriteTimeout;
                submitStream.WriteTimeout = ReadWriteTimeout;
            }
            if(Logging.On)Logging.Associate(Logging.Web, this, submitStream);

            // The CBT won't actually be valid until we write to the stream for the first time, but we can create
            // the TransportContext now.  We don't query it until later, when we know it's available.
            TransportContext transportContext = new ConnectStreamContext(submitStream);
            ServerAuthenticationState.TransportContext = transportContext;
            ProxyAuthenticationState.TransportContext = transportContext;

            _SubmitWriteStream = submitStream;

            // Async RTC requests only.  Skip if ApplySetting has not been called so we can test
            // without IOControl support/workarounds.
            if (RtcState != null && RtcState.inputData != null && !RtcState.IsAborted)
            {
                RtcState.outputData = new byte[sizeof(RtcState.ControlChannelTriggerStatus)];
                RtcState.result = _SubmitWriteStream.SetRtcOption(RtcState.inputData, RtcState.outputData);
                if (!RtcState.IsEnabled())
                {
                    // Abort request if we weren't able to enable RTC.
                    Abort(null, AbortState.Public);
                }
                RtcState.connectComplete.Set();
            }

            //
            // This line is needed ONLY if we got a connect failure (Abort can still happen at random time)
            // CallDone will check for the write side response processing and this is what we want.
            // Note that [....] case already has a separate path to check for the response
            //
            if (Async && _CoreResponse != null && (object)_CoreResponse != (object)DBNull.Value)
            {
                GlobalLog.Assert(_CoreResponse is Exception, "SetRequestSubmitDone()|Found offensive response right after getting connection ({0}).", _CoreResponse);
                submitStream.CallDone();
                GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone() - already have a core response", _CoreResponse.GetType().FullName);
                return;
            }

            EndSubmitRequest();
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::SetRequestSubmitDone");
        }
Пример #3
0
        /// <devdoc>
        ///  <para>Retreives the Request Stream after an Async operation has completed </para>
        /// </devdoc>
        public Stream EndGetRequestStream(IAsyncResult asyncResult, out TransportContext context)
        {
#if DEBUG
            using (GlobalLog.SetThreadKind(ThreadKinds.User)) {
#endif
            GlobalLog.Enter("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(asyncResult));
            if(Logging.On)Logging.Enter(Logging.Web, this, "EndGetRequestStream", "");

            context = null;

            //
            // parameter validation
            //
            if (asyncResult == null) {
                throw new ArgumentNullException("asyncResult");
            }
            LazyAsyncResult castedAsyncResult = asyncResult as LazyAsyncResult;
            if (castedAsyncResult==null || castedAsyncResult.AsyncObject!=this) {
                throw new ArgumentException(SR.GetString(SR.net_io_invalidasyncresult), "asyncResult");
            }
            if (castedAsyncResult.EndCalled) {
                throw new InvalidOperationException(SR.GetString(SR.net_io_invalidendcall, "EndGetRequestStream"));
            }

            ConnectStream connectStream = castedAsyncResult.InternalWaitForCompletion() as ConnectStream;
            castedAsyncResult.EndCalled = true;

            if (connectStream == null)
            {
                if (Logging.On) Logging.Exception(Logging.Web, this, "EndGetRequestStream", castedAsyncResult.Result as Exception);
                throw (Exception) castedAsyncResult.Result;
            }

            context = new ConnectStreamContext(connectStream);

            // Otherwise it worked, so return the HttpWebResponse.
            GlobalLog.Leave("HttpWebRequest#" + ValidationHelper.HashString(this) + "::EndGetRequestStream", ValidationHelper.HashString(connectStream));
            if(Logging.On)Logging.Exit(Logging.Web, this, "EndGetRequestStream", connectStream);

            FrameworkEventSource.Log.EndGetRequestStream(this);

            return connectStream;
#if DEBUG
            }
#endif
        }