Ejemplo n.º 1
0
        /*++
            WriteHeaders

            This function writes header data to the network. Headers are special
            in that they don't have any non-header transforms applied to them,
            and are not subject to content-length constraints. We just write them
            through, and if we're done writing headers we tell the connection that.

            Returns:
                WebExceptionStatus.Pending      - we don't have a stream yet.
                WebExceptionStatus.SendFailure  - there was an error while writing to the wire.
                WebExceptionStatus.Success      - success.

        --*/
        internal void WriteHeaders(bool async) {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders", "Connection#" + ValidationHelper.HashString(m_Connection) + ", headers buffer size = " + m_Request.WriteBufferLength.ToString());

            WebExceptionStatus error =  WebExceptionStatus.SendFailure;

            if (!ErrorInStream)
            {
                //m_Request.WriteBuffer may be set to null on resubmit before method exits
                byte[] writeBuffer = m_Request.WriteBuffer;
                int writeBufferLength = m_Request.WriteBufferLength;
                
                try
                {
                    Interlocked.CompareExchange(ref m_CallNesting, Nesting.InternalIO, Nesting.Idle);
                    GlobalLog.Print("WriteHeaders() callNesting: " + m_CallNesting.ToString());

                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_sending_headers, m_Request.Headers.ToString(true)));

                    if(async)
                    {
                        WriteHeadersCallbackState state = new WriteHeadersCallbackState(m_Request, this);
                        IAsyncResult ar = m_Connection.UnsafeBeginWrite(writeBuffer,0,writeBufferLength, m_WriteHeadersCallback, state);
                        if (ar.CompletedSynchronously) {
                            m_Connection.EndWrite(ar);
                            error = WebExceptionStatus.Success;
                        }
                        else {
                            error = WebExceptionStatus.Pending;
#if DEBUG
                            _PendingResult = ar;
#endif
                        }
                    }
                    else
                    {
                        SafeSetSocketTimeout(SocketShutdown.Send);
                        m_Connection.Write(writeBuffer, 0, writeBufferLength);
                        error = WebExceptionStatus.Success;
                    }
                }
                catch (Exception e) {
                    HandleWriteHeadersException(e, error);
                }
                finally {
                    if(error != WebExceptionStatus.Pending) {
                        Interlocked.CompareExchange(ref m_CallNesting, Nesting.Idle, Nesting.InternalIO);
                        GlobalLog.Print("WriteHeaders() callNesting: " + m_CallNesting.ToString());
                    }
                }
            }
            else
            {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders() ignoring since ErrorInStream = true");
            }

            if (error == WebExceptionStatus.Pending) 
            {
                return; // WriteHeadersCallback will finish this async
            }

            if (error == WebExceptionStatus.Success && !ErrorInStream)
            {
                error = WebExceptionStatus.ReceiveFailure;

                // Start checking for responses.  This needs to happen outside of the Nesting.InternalIO lock 
                // because it may receive, process, and start a resubmit.
                try
                {
                    if (async)
                    {
                        m_Request.StartAsync100ContinueTimer();
                        m_Connection.CheckStartReceive(m_Request);
                    }
                    else 
                    {
                        m_Request.StartContinueWait();
                        m_Connection.CheckStartReceive(m_Request);
                        if (m_Request.ShouldWaitFor100Continue()) // Sync poll
                        {
                            PollAndRead(m_Request.UserRetrievedWriteStream);
                        }
                    }
                    error = WebExceptionStatus.Success;
                }
                catch (Exception e)
                {
                    HandleWriteHeadersException(e, error);
                }
            }

            m_Request.WriteHeadersCallback(error, this, async);            
            m_Request.FreeWriteBuffer();
        }
        /*++
            WriteHeaders

            This function writes header data to the network. Headers are special
            in that they don't have any non-header transforms applied to them,
            and are not subject to content-length constraints. We just write them
            through, and if we're done writing headers we tell the connection that.

            Returns:
                WebExceptionStatus.Pending      - we don't have a stream yet.
                WebExceptionStatus.SendFailure  - there was an error while writing to the wire.
                WebExceptionStatus.Success      - success.

        --*/
        internal void WriteHeaders(bool async) {
            GlobalLog.Enter("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders", "Connection#" + ValidationHelper.HashString(m_Connection) + ", headers buffer size = " + m_Request.WriteBuffer.Length.ToString());

            WebExceptionStatus error =  WebExceptionStatus.SendFailure;

            if (!ErrorInStream)
            {
                //m_Request.WriteBuffer may be set to null on resubmit before method exits
                byte[] writeBuffer = m_Request.WriteBuffer;
                
                try
                {
                    Interlocked.CompareExchange(ref m_CallNesting, Nesting.InternalIO, Nesting.Idle);
                    GlobalLog.Print("WriteHeaders() callNesting: " + m_CallNesting.ToString());

                    if(async)
                    {
                        WriteHeadersCallbackState state = new WriteHeadersCallbackState(m_Request, this);
                        IAsyncResult ar = m_Connection.UnsafeBeginWrite(writeBuffer,0,writeBuffer.Length, m_WriteHeadersCallback, state);
                        if (ar.CompletedSynchronously) {
                            m_Connection.EndWrite(ar);
                            m_Connection.CheckStartReceive(m_Request);
                            error = WebExceptionStatus.Success;
                        }
                        else {
                            error = WebExceptionStatus.Pending;
#if DEBUG
                            _PendingResult = ar;
#endif
                        }
                    }
                    else
                    {
                        SafeSetSocketTimeout(SocketShutdown.Send);
                        m_Connection.Write(writeBuffer, 0, writeBuffer.Length);
                        m_Connection.CheckStartReceive(m_Request);
                        error = WebExceptionStatus.Success;
                    }

                    if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_sending_headers, m_Request.Headers.ToString(true)));
                }
                catch (Exception e) {

                    if (NclUtilities.IsFatal(e)) throw;

                    GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders Exception: "+e.ToString());
                    
                    if (e is IOException || e is ObjectDisposedException)
                    {
                        //new connection but reset from server on inital send
                        if(!m_Connection.AtLeastOneResponseReceived && !m_Request.BodyStarted){
                            e = new WebException(
                                NetRes.GetWebStatusString("net_connclosed", error),
                                error,
                                WebExceptionInternalStatus.Recoverable,
                                e);
                        }
                        else{
                            e = new WebException(
                                            NetRes.GetWebStatusString("net_connclosed", error),
                                            error,
                                            m_Connection.AtLeastOneResponseReceived ? WebExceptionInternalStatus.Isolated : WebExceptionInternalStatus.RequestFatal,
                                            e);
                        }
                    }

                    IOError(e, false);
                }
                finally {
                    if(error != WebExceptionStatus.Pending) {
                        Interlocked.CompareExchange(ref m_CallNesting, Nesting.Idle, Nesting.InternalIO);
                        GlobalLog.Print("WriteHeaders() callNesting: " + m_CallNesting.ToString());
                    }
                }

            }
            else
            {
                GlobalLog.Print("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders() ignoring since ErrorInStream = true");
            }

            if(error != WebExceptionStatus.Pending) {
                //if error is Pending, and this is async, the request callback will be invoked from the stream callback.
                m_Request.WriteHeadersCallback(error, this, async);
            }

            GlobalLog.Leave("ConnectStream#" + ValidationHelper.HashString(this) + "::WriteHeaders", error.ToString());
        }