/*++ 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()); }