Code:
/ DotNET / DotNET / 8.0 / untmp / whidbey / REDBITS / ndp / fx / src / Net / System / Net / _ListenerResponseStream.cs / 1 / _ListenerResponseStream.cs
// ------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // // ----------------------------------------------------------------------------- namespace System.Net { using System.IO; using System.Runtime.InteropServices; using System.ComponentModel; using System.Threading; using System.Collections; using System.Globalization; using System.Security.Permissions; unsafe class HttpResponseStream : Stream { private HttpListenerContext m_HttpContext; private long m_LeftToWrite = long.MinValue; private bool m_Closed; internal HttpResponseStream(HttpListenerContext httpContext) { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::.ctor() HttpListenerContext##" + ValidationHelper.HashString(httpContext)); m_HttpContext = httpContext; } internal UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS ComputeLeftToWrite() { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::ComputeLeftToWrite() on entry m_LeftToWrite:" + m_LeftToWrite); UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; if (!m_HttpContext.Response.ComputedHeaders) { flags = m_HttpContext.Response.ComputeHeaders(); } if (m_LeftToWrite==long.MinValue) { UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = m_HttpContext.GetKnownMethod(); m_LeftToWrite = method != UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD ? m_HttpContext.Response.ContentLength64 : 0; GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::ComputeLeftToWrite() computed m_LeftToWrite:" + m_LeftToWrite); if (m_LeftToWrite==0) { Close(); } else if (method==UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbOPTIONS && m_LeftToWrite > 0) { throw new ProtocolViolationException(SR.GetString(SR.net_nouploadonget)); } } return flags; } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return true; } } public override bool CanRead { get { return false; } } /* public bool DataAvailable { get { throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream)); } } */ public override void Flush() { } public override long Length { get { throw new NotSupportedException(SR.GetString(SR.net_noseek)); } } public override long Position { get { throw new NotSupportedException(SR.GetString(SR.net_noseek)); } set { throw new NotSupportedException(SR.GetString(SR.net_noseek)); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(SR.GetString(SR.net_noseek)); } public override void SetLength(long value) { throw new NotSupportedException(SR.GetString(SR.net_noseek)); } public override int Read([In, Out] byte[] buffer, int offset, int size) { throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream)); } [HostProtection(ExternalThreading=true)] public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, object state) { throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream)); } public override int EndRead(IAsyncResult asyncResult) { throw new InvalidOperationException(SR.GetString(SR.net_writeonlystream)); } public override void Write(byte[] buffer, int offset, int size) { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Write", ""); GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Write() buffer.Length:" + buffer.Length + " size:" + size + " offset:" + offset); if (buffer==null) { throw new ArgumentNullException("buffer"); } if (offset<0 || offset>buffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (size<0 || size>buffer.Length-offset) { throw new ArgumentOutOfRangeException("size"); } UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); if (size==0 || m_Closed) { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Write", ""); return; } if (m_LeftToWrite>0 && size>m_LeftToWrite) { throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig)); } uint statusCode; uint dataToWrite = (uint)size; SafeLocalFree bufferAsIntPtr = null; IntPtr pBufferAsIntPtr = IntPtr.Zero; bool sentHeaders = m_HttpContext.Response.SentHeaders; try { fixed (byte *pDataBuffer = buffer) { byte *pBuffer = pDataBuffer; if (m_HttpContext.Response.BoundaryType==BoundaryType.Chunked) { // string chunkHeader = size.ToString("x", CultureInfo.InvariantCulture); dataToWrite = dataToWrite + (uint)(chunkHeader.Length + 4); bufferAsIntPtr = SafeLocalFree.LocalAlloc((int)dataToWrite); pBufferAsIntPtr = bufferAsIntPtr.DangerousGetHandle(); for (int i=0; ibuffer.Length) { throw new ArgumentOutOfRangeException("offset"); } if (size<0 || size>buffer.Length-offset) { throw new ArgumentOutOfRangeException("size"); } UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); if (size==0 || m_Closed) { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "BeginWrite", ""); HttpResponseStreamAsyncResult result = new HttpResponseStreamAsyncResult(this, state, callback); result.InvokeCallback((uint) 0); return result; } if (m_LeftToWrite>0 && size>m_LeftToWrite) { throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig)); } uint statusCode; flags |= m_LeftToWrite==size ? UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE : UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA; bool sentHeaders = m_HttpContext.Response.SentHeaders; HttpResponseStreamAsyncResult asyncResult = new HttpResponseStreamAsyncResult(this, state, callback, buffer, offset, size, m_HttpContext.Response.BoundaryType==BoundaryType.Chunked, sentHeaders); if (!sentHeaders) { statusCode = m_HttpContext.Response.SendHeaders(null, asyncResult, flags); } else { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody"); m_HttpContext.EnsureBoundHandle(); statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( m_HttpContext.RequestQueueHandle, m_HttpContext.RequestId, (uint)flags, asyncResult.dataChunkCount, asyncResult.pDataChunks, null, SafeLocalFree.Zero, 0, asyncResult.m_pOverlapped, null); GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode); if (m_HttpContext.Listener.IgnoreWriteExceptions) { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::BeginWrite() suppressing error"); statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; } } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_IO_PENDING) { Exception exception = new HttpListenerException((int)statusCode); if(Logging.On)Logging.Exception(Logging.HttpListener, this, "BeginWrite", exception); m_HttpContext.Abort(); throw exception; } if(Logging.On)Logging.Exit(Logging.HttpListener, this, "BeginWrite", ""); return asyncResult; } public override void EndWrite(IAsyncResult asyncResult) { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "EndWrite", ""); GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite() asyncResult#" + ValidationHelper.HashString(asyncResult)); if (asyncResult==null) { throw new ArgumentNullException("asyncResult"); } HttpResponseStreamAsyncResult castedAsyncResult = asyncResult as HttpResponseStreamAsyncResult; 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, "EndWrite")); } castedAsyncResult.EndCalled = true; // wait & then check for errors object returnValue = castedAsyncResult.InternalWaitForCompletion(); Exception exception = returnValue as Exception; if (exception!=null) { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite() rethrowing exception:" + exception); if(Logging.On)Logging.Exception(Logging.HttpListener, this, "EndWrite", exception); m_HttpContext.Abort(); throw exception; } // UpdateAfterWrite((uint)returnValue); GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::EndWrite()"); if(Logging.On)Logging.Exit(Logging.HttpListener, this, "EndWrite", ""); } void UpdateAfterWrite(uint dataWritten) { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::UpdateAfterWrite() dataWritten:" + dataWritten + " m_LeftToWrite:" + m_LeftToWrite + " m_Closed:" + m_Closed); if (m_LeftToWrite>0) { // keep track of the data transferred m_LeftToWrite -= dataWritten; } if (m_LeftToWrite==0) { // in this case we already passed 0 as the flag, so we don't need to call HttpSendResponseEntityBody() when we Close() m_Closed = true; } GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::UpdateAfterWrite() dataWritten:" + dataWritten + " m_LeftToWrite:" + m_LeftToWrite + " m_Closed:" + m_Closed); } protected override void Dispose(bool disposing) { if(Logging.On)Logging.Enter(Logging.HttpListener, this, "Close", ""); try { if(disposing){ GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() m_Closed:" + m_Closed); if (m_Closed) { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Close", ""); return; } m_Closed = true; UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS flags = ComputeLeftToWrite(); if (m_LeftToWrite>0) { throw new InvalidOperationException(SR.GetString(SR.net_io_notenoughbyteswritten)); } bool sentHeaders = m_HttpContext.Response.SentHeaders; if (sentHeaders && m_LeftToWrite==0) { if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Close", ""); return; } uint statusCode = 0; if ((m_HttpContext.Response.BoundaryType==BoundaryType.Chunked || m_HttpContext.Response.BoundaryType==BoundaryType.None) && (String.Compare(m_HttpContext.Request.HttpMethod, "HEAD", StringComparison.OrdinalIgnoreCase)!=0)) { if (m_HttpContext.Response.BoundaryType==BoundaryType.None) { flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT; } fixed (void* pBuffer = NclConstants.ChunkTerminator) { UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunk = null; if (m_HttpContext.Response.BoundaryType==BoundaryType.Chunked) { UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK dataChunk = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); dataChunk.DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; dataChunk.pBuffer = (byte *)pBuffer; dataChunk.BufferLength = (uint) NclConstants.ChunkTerminator.Length; pDataChunk = &dataChunk; } if (!sentHeaders) { statusCode = m_HttpContext.Response.SendHeaders(pDataChunk, null, flags); } else { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() calling UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody"); statusCode = UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody( m_HttpContext.RequestQueueHandle, m_HttpContext.RequestId, (uint)flags, pDataChunk!=null ? (ushort)1 : (ushort)0, pDataChunk, null, SafeLocalFree.Zero, 0, null, null); GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() call to UnsafeNclNativeMethods.HttpApi.HttpSendResponseEntityBody returned:" + statusCode); if (m_HttpContext.Listener.IgnoreWriteExceptions) { GlobalLog.Print("HttpResponseStream#" + ValidationHelper.HashString(this) + "::Close() suppressing error"); statusCode = UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS; } } } } else { if (!sentHeaders) { statusCode = m_HttpContext.Response.SendHeaders(null, null, flags); } } if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { Exception exception = new HttpListenerException((int)statusCode); if(Logging.On)Logging.Exception(Logging.HttpListener, this, "Close", exception); m_HttpContext.Abort(); throw exception; } m_LeftToWrite = 0; } } finally { base.Dispose(disposing); } if(Logging.On)Logging.Exit(Logging.HttpListener, this, "Dispose", ""); } } unsafe class HttpResponseStreamAsyncResult : LazyAsyncResult { internal NativeOverlapped* m_pOverlapped; private UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[] m_DataChunks; internal bool m_SentHeaders; private static readonly IOCompletionCallback s_IOCallback = new IOCompletionCallback(Callback); internal ushort dataChunkCount { get { return (ushort)m_DataChunks.Length; } } internal UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK* pDataChunks { get { return (UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(m_DataChunks, 0)); } } internal HttpResponseStreamAsyncResult(object asyncObject, object userState, AsyncCallback callback) : base(asyncObject, userState, callback) { } internal HttpResponseStreamAsyncResult(object asyncObject, object userState, AsyncCallback callback, byte[] buffer, int offset, int size, bool chunked, bool sentHeaders): base(asyncObject, userState, callback){ m_SentHeaders = sentHeaders; Overlapped overlapped = new Overlapped(); overlapped.AsyncResult = this; m_DataChunks = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1]; GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(this) + "::.ctor() m_pOverlapped:0x" + ((IntPtr)m_pOverlapped).ToString("x8")); object[] objectsToPin = new object[1 + m_DataChunks.Length]; objectsToPin[m_DataChunks.Length] = m_DataChunks; int chunkHeaderOffset = 0; byte[] chunkHeaderBuffer = null; if (chunked) { chunkHeaderBuffer = ConnectStream.GetChunkHeader(size, out chunkHeaderOffset); m_DataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); m_DataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; m_DataChunks[0].BufferLength = (uint)(chunkHeaderBuffer.Length - chunkHeaderOffset); objectsToPin[0] = chunkHeaderBuffer; m_DataChunks[1] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); m_DataChunks[1].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; m_DataChunks[1].BufferLength = (uint)size; objectsToPin[1] = buffer; m_DataChunks[2] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); m_DataChunks[2].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; m_DataChunks[2].BufferLength = (uint) NclConstants.CRLF.Length; objectsToPin[2] = NclConstants.CRLF; } else { m_DataChunks[0] = new UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK(); m_DataChunks[0].DataChunkType = UnsafeNclNativeMethods.HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory; m_DataChunks[0].BufferLength = (uint)size; objectsToPin[0] = buffer; } // This call will pin needed memory m_pOverlapped = overlapped.Pack(s_IOCallback, objectsToPin); if (chunked) { m_DataChunks[0].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(chunkHeaderBuffer, chunkHeaderOffset)); m_DataChunks[1].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); m_DataChunks[2].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(NclConstants.CRLF, 0)); } else { m_DataChunks[0].pBuffer = (byte*)(Marshal.UnsafeAddrOfPinnedArrayElement(buffer, offset)); } } private static unsafe void Callback(uint errorCode, uint numBytes, NativeOverlapped* nativeOverlapped) { Overlapped callbackOverlapped = Overlapped.Unpack(nativeOverlapped); HttpResponseStreamAsyncResult asyncResult = callbackOverlapped.AsyncResult as HttpResponseStreamAsyncResult; GlobalLog.Print("HttpResponseStreamAsyncResult#" + ValidationHelper.HashString(asyncResult) + "::Callback() errorCode:0x" + errorCode.ToString("x8") + " numBytes:" + numBytes + " nativeOverlapped:0x" + ((IntPtr)nativeOverlapped).ToString("x8")); object result = null; try { if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF) { asyncResult.ErrorCode = (int)errorCode; result = new HttpListenerException((int)errorCode); } else { // if we sent headers and body together, numBytes will be the total, but we need to only account for the data // result = numBytes; result = asyncResult.m_DataChunks.Length==1 ? asyncResult.m_DataChunks[0].BufferLength : 0; if(Logging.On){for (int i=0; i
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- QilXmlWriter.cs
- LogSwitch.cs
- XmlTypeMapping.cs
- SiteMapSection.cs
- ToggleProviderWrapper.cs
- Component.cs
- XmlValidatingReader.cs
- DefaultValueAttribute.cs
- EncryptedKey.cs
- BaseValidatorDesigner.cs
- EmbeddedMailObject.cs
- DefaultBinder.cs
- Baml2006ReaderSettings.cs
- DesignerActionUI.cs
- AssertFilter.cs
- FormViewRow.cs
- DataBoundControlParameterTarget.cs
- SQLDecimal.cs
- WebServiceReceive.cs
- SymmetricAlgorithm.cs
- DbCommandDefinition.cs
- GeneralTransformGroup.cs
- FormsAuthenticationUser.cs
- EventToken.cs
- SocketManager.cs
- DataBoundControlHelper.cs
- Speller.cs
- XsltContext.cs
- FrugalMap.cs
- LayoutEngine.cs
- NonVisualControlAttribute.cs
- ColorInterpolationModeValidation.cs
- InternalDispatchObject.cs
- SourceInterpreter.cs
- VisualTreeHelper.cs
- AccessDataSource.cs
- UserMapPath.cs
- DockProviderWrapper.cs
- DeferredElementTreeState.cs
- EntityProxyFactory.cs
- Tablet.cs
- HtmlDocument.cs
- LookupNode.cs
- MonthChangedEventArgs.cs
- OptimalBreakSession.cs
- DrawingCollection.cs
- XmlNamespaceDeclarationsAttribute.cs
- MethodImplAttribute.cs
- ListBoxAutomationPeer.cs
- DataSourceDescriptorCollection.cs
- InitialServerConnectionReader.cs
- XmlWriterTraceListener.cs
- Vector3D.cs
- TextEvent.cs
- RelationshipFixer.cs
- StorageMappingItemLoader.cs
- BufferAllocator.cs
- BindingExpression.cs
- SoapMessage.cs
- EastAsianLunisolarCalendar.cs
- ExceptionTrace.cs
- UrlMappingsSection.cs
- WebPartVerb.cs
- SmiRequestExecutor.cs
- LinearQuaternionKeyFrame.cs
- FilterException.cs
- DesignerSerializationVisibilityAttribute.cs
- ILGenerator.cs
- InvokeGenerator.cs
- CodeCompiler.cs
- DesignerSerializationVisibilityAttribute.cs
- TreeViewItem.cs
- _Semaphore.cs
- XmlSchemaSimpleContentExtension.cs
- Selection.cs
- HandlerWithFactory.cs
- DriveNotFoundException.cs
- Italic.cs
- DllNotFoundException.cs
- EventHandlerList.cs
- EffectiveValueEntry.cs
- TreeNodeClickEventArgs.cs
- MultilineStringConverter.cs
- DataGridViewColumnDividerDoubleClickEventArgs.cs
- IntegerCollectionEditor.cs
- TextEditor.cs
- EventLog.cs
- DataGridColumnCollection.cs
- DataExchangeServiceBinder.cs
- ScrollBarAutomationPeer.cs
- XPathDocumentBuilder.cs
- documentsequencetextpointer.cs
- dbdatarecord.cs
- SchemaDeclBase.cs
- FacetDescriptionElement.cs
- UnsafeNativeMethodsMilCoreApi.cs
- ellipse.cs
- FormViewPagerRow.cs
- StopStoryboard.cs
- OracleSqlParser.cs