HttpWebListener() { int result = ComNetOS.IsWinNt ? UlSysApi.UlCreateAppPool( ref m_AppPoolHandle, string.Empty, IntPtr.Zero, UlConstants.UL_OPTION_OVERLAPPED) : UlVxdApi.UlCreateAppPool( ref m_AppPoolHandle); if (result != NativeMethods.ERROR_SUCCESS) { throw new InvalidOperationException("UlCreateAppPool() failed, err#" + Convert.ToString(result)); } // // we count the number of instances so that in the destructor we are // able to correctly call UlTerminate() and be gracefully shutdown the // driver when this process no longer needs it // m_InstancesCounter++; GlobalLog.Print("UlCreateAppPool() succesfull, AppPool handle is " + Convert.ToString(m_AppPoolHandle)); return; } // WebListener()
RemoveUriPrefix( string uriPrefix) { if (!m_UriPrefixes.Contains(uriPrefix)) { return(false); } int result = ComNetOS.IsWinNt ? UlSysApi.UlRemoveTransientUrl( m_AppPoolHandle, uriPrefix) : UlVxdApi.UlUnregisterUri( m_AppPoolHandle, uriPrefix); if (result != NativeMethods.ERROR_SUCCESS) { throw new InvalidOperationException("UlUnregisterUri() failed"); } m_UriPrefixes.Remove(uriPrefix); return(true); } // RemoveUriPrefix()
AddUriPrefix( string uriPrefix) { //check permissions for URI being listened (new WebPermission(NetworkAccess.Accept, uriPrefix)).Demand(); int result = ComNetOS.IsWinNt ? UlSysApi.UlAddTransientUrl( m_AppPoolHandle, uriPrefix) : UlVxdApi.UlRegisterUri( m_AppPoolHandle, uriPrefix); if (result != NativeMethods.ERROR_SUCCESS) { throw new InvalidOperationException("UlRegisterUri() failed, err#" + Convert.ToString(result)); } GlobalLog.Print("AddUriPrefix( " + uriPrefix + " ) handle:" + Convert.ToString(m_AppPoolHandle)); m_UriPrefixes.Add(uriPrefix); return(true); } // AddUriPrefix()
Close() { RemoveAll(); if (m_InstancesCounter-- == 0) { if (ComNetOS.IsWinNt) { UlSysApi.UlTerminate(); } else { UlVxdApi.UlTerminate(); } } return; } // Close()
} // Position public override int Read( [In, Out] byte[] buffer, int offset, int count) { GlobalLog.Print("ListenerRequestStream.ReadCore() offset: " + Convert.ToString(offset) + " count:" + Convert.ToString(count)); int DataCopiedFromBuffer = 0; int DataCopiedFromDriver = 0; // // see if we still have some data in the buffer // if (m_BufferedDataExists) { // // start sending data in the buffer // DataCopiedFromBuffer = Math.Min( m_DataBuffer.Length - m_DataBufferOffset, count); Buffer.BlockCopy( m_DataBuffer, m_DataBufferOffset, buffer, offset, DataCopiedFromBuffer); // // update the offset for the buffered data for subsequent calls // m_DataBufferOffset += DataCopiedFromBuffer; m_BufferedDataExists = m_DataBuffer.Length > m_DataBufferOffset; // // update offset and count in the buffer for subsequent calls // offset += DataCopiedFromBuffer; count -= DataCopiedFromBuffer; } // // if all the data requested was handled by the buffered data we don't // need to call the driver for more, so we just return here // if (count <= 0 || !m_MoreToRead) { return(DataCopiedFromBuffer); } // // otherwise pin the buffer and make an unmanaged call to the driver to // read more entity body // GCHandle PinnedBuffer; IntPtr AddrOfPinnedBuffer = IntPtr.Zero; PinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject(); // // issue unmanaged blocking call // int result = ComNetOS.IsWinNt ? UlSysApi.UlReceiveEntityBody( m_AppPoolHandle, m_RequestId, UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY, AddrOfPinnedBuffer, count, ref DataCopiedFromDriver, IntPtr.Zero) : UlVxdApi.UlReceiveHttpRequestEntityBody( m_AppPoolHandle, m_RequestId, 0, AddrOfPinnedBuffer, count, ref DataCopiedFromDriver, IntPtr.Zero); PinnedBuffer.Free(); if (result != NativeMethods.ERROR_SUCCESS && result != NativeMethods.ERROR_HANDLE_EOF) { // // Consider: move all Exception string to system.txt for localization // throw new InvalidOperationException("UlReceiveEntityBody() failed, err#" + Convert.ToString(result)); } return(DataCopiedFromBuffer + DataCopiedFromDriver); } // Read()
public override void Close() { if (m_Closed) { return; } m_Closed = true; // // we need to flush ul in order to tell it that we have no more data // to send in the entity body, and if we're chunk-encoding we need to // send the trailer chunk // if (m_SendChunked == true) { // // send the trailer // } int DataWritten = 0; int result = ComNetOS.IsWinNt ? UlSysApi.UlSendEntityBody( m_AppPoolHandle, m_RequestId, 0, 0, IntPtr.Zero, ref DataWritten, IntPtr.Zero) : UlVxdApi.UlSendHttpResponseEntityBody( m_AppPoolHandle, m_RequestId, 0, 0, IntPtr.Zero, ref DataWritten, IntPtr.Zero); GlobalLog.Print("UlSendHttpResponseEntityBody(0) DataWritten: " + Convert.ToString(DataWritten)); // // ignore return value??? // if (result != NativeMethods.ERROR_SUCCESS && result != NativeMethods.ERROR_HANDLE_EOF) { GlobalLog.Print("sync UlSendHttpResponseEntityBody(0) failed, err#" + Convert.ToString(result)); // throw new InvalidOperationException( "UlSendHttpResponseEntityBody() failed, err#" + Convert.ToString( result ) ); } return; } // Close()
} // Position // // write a chunk of data to ul // public override void Write( byte[] buffer, int offset, int count) { GlobalLog.Print("ListenerResponseStream.WriteCore() offset: " + Convert.ToString(offset) + " count:" + Convert.ToString(count)); if (m_ContentLength != -1 && m_ContentLength < count) { // // user can't send more data than specified in the ContentLength // throw new ProtocolViolationException(SR.GetString(SR.net_entitytoobig)); } int DataToWrite = count; GCHandle PinnedBuffer = new GCHandle(); IntPtr AddrOfPinnedBuffer = IntPtr.Zero; if (m_SendChunked) { string ChunkHeader = "0x" + Convert.ToString(count, 16); DataToWrite += ChunkHeader.Length + 4; AddrOfPinnedBuffer = Marshal.AllocHGlobal(DataToWrite); Marshal.Copy(ChunkHeader.ToCharArray(), 0, AddrOfPinnedBuffer, ChunkHeader.Length); Marshal.WriteInt16(AddrOfPinnedBuffer, ChunkHeader.Length, 0x0A0D); Marshal.Copy((byte[])buffer, offset, IntPtrHelper.Add(AddrOfPinnedBuffer, ChunkHeader.Length + 2), count); Marshal.WriteInt16(AddrOfPinnedBuffer, DataToWrite - 2, 0x0A0D); } else { // // pin the buffer and make an unmanaged call to the driver to // write more entity body // PinnedBuffer = GCHandle.Alloc(buffer, GCHandleType.Pinned); AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject(); } // // set up a UL_DATA_CHUNK structure to pass down to UL with pointers // to data to be written // IntPtr AddrOfPinnedEntityChunks = Marshal.AllocHGlobal(32); // // AddrOfPinnedBuffer and count go into a pEntityChunks structure // Marshal.WriteInt64(AddrOfPinnedEntityChunks, 0, 0); Marshal.WriteIntPtr(AddrOfPinnedEntityChunks, 8, AddrOfPinnedBuffer); Marshal.WriteInt32(AddrOfPinnedEntityChunks, 12, DataToWrite); Marshal.WriteInt64(AddrOfPinnedEntityChunks, 16, 0); Marshal.WriteInt64(AddrOfPinnedEntityChunks, 24, 0); GlobalLog.Print("Calling UlSendHttpResponseEntityBody: AddrOfPinnedEntityChunks:" + Convert.ToString(AddrOfPinnedEntityChunks) + " AddrOfPinnedBuffer:" + Convert.ToString(AddrOfPinnedBuffer) + " DataToWrite:" + Convert.ToString(DataToWrite)); // // issue unmanaged blocking call // int DataWritten = 0; int result = ComNetOS.IsWinNt ? UlSysApi.UlSendEntityBody( m_AppPoolHandle, m_RequestId, UlConstants.UL_SEND_RESPONSE_FLAG_MORE_DATA, 1, AddrOfPinnedEntityChunks, ref DataWritten, IntPtr.Zero) : UlVxdApi.UlSendHttpResponseEntityBody( m_AppPoolHandle, m_RequestId, 0, 1, AddrOfPinnedEntityChunks, ref DataWritten, IntPtr.Zero); if (m_SendChunked) { // // data was copied into an unmanaged buffer, free it // Marshal.FreeHGlobal(AddrOfPinnedBuffer); } else { // // data wasn't copied unpin the pinned buffer // PinnedBuffer.Free(); } Marshal.FreeHGlobal(AddrOfPinnedEntityChunks); GlobalLog.Print("UlSendHttpResponseEntityBody() DataWritten:" + Convert.ToString(DataWritten) + " DataToWrite:" + Convert.ToString(DataToWrite)); if (result != NativeMethods.ERROR_SUCCESS) //Win32.ERROR_CANCELLED || Win32.ERROR_BAD_COMMAND || NativeMethods.ERROR_INVALID_PARAMETER { throw new ProtocolViolationException(SR.GetString(SR.net_connclosed) + Convert.ToString(result)); } // // double check the number of bytes written // if (DataWritten != DataToWrite) { throw new InvalidOperationException("sync UlSendHttpResponseEntityBody() failed to write all the data" + " count:" + Convert.ToString(count) + " DataWritten:" + Convert.ToString(DataWritten) + " DataToWrite:" + Convert.ToString(DataToWrite) + " m_AppPoolHandle:" + Convert.ToString(m_AppPoolHandle) + " m_RequestId:" + Convert.ToString(m_RequestId) + " err#" + Convert.ToString(result)); } if (result != NativeMethods.ERROR_SUCCESS && result != NativeMethods.ERROR_HANDLE_EOF) { // // Consider: move all Exception string to system.txt for localization // throw new InvalidOperationException("sync UlSendHttpResponseEntityBody() failed, err#" + Convert.ToString(result)); } if (m_ContentLength != -1) { // // keep track of the data transferred // m_ContentLength -= count; if (m_ContentLength == 0) { // // I should be able to call Close() at this point // } } return; // DataToWrite; } // Write()
/// <include file='doc\HttpListenerWebResponse.uex' path='docs/doc[@for="HttpListenerWebResponse.GetResponseStream"]/*' /> /// <devdoc> /// <para>[To be supplied.]</para> /// </devdoc> public override Stream GetResponseStream() { GlobalLog.Print("entering GetResponseStream()"); // // check if the Stream was already handed to the user before // if (m_ResponseStream != null) { return(m_ResponseStream); } // // CODEWORK: replace the bool variable with a check on the minimal // info that NEEDS to be set in a HTTP Response in order to send // the headers // if (m_StatusDescription == null || !m_ReadyToSendHeaders) { throw new InvalidOperationException(SR.GetString()); } // // handing off the Stream object out of WebResponse, implies that // we're ready to send the response headers back to the client // int myFlags = 0; // // check ContentLength consistency // m_SendChunked = false; m_KeepAlive = true; if (m_ContentLength == -1) { // // server didn't specify response content length // if (m_ClientVersion.Major < 1 || (m_ClientVersion.Major == 1 && m_ClientVersion.Minor < 1)) { // // make sure there's no Keep-Alive header specified // m_WebHeaders.RemoveInternal(HttpKnownHeaderNames.KeepAlive); m_KeepAlive = false; } else if (m_ClientVersion.Major == 1) { // // we need to chunk the response, regardless of what the // user wanted to do // m_WebHeaders.AddInternal(HttpKnownHeaderNames.TransferEncoding, "chunked"); m_SendChunked = true; } else { // // this protocol version is not supported? ul should have // responded with a 503 // throw new ProtocolViolationException(SR.GetString(SR.net_invalidversion)); } } else { m_WebHeaders.ChangeInternal(HttpKnownHeaderNames.ContentLength, Convert.ToString(m_ContentLength)); myFlags = UlConstants.UL_SEND_RESPONSE_FLAG_MORE_DATA; } // // I'm going to make this REALLY inefficient, I'll fix it later // CODEWORK: make this incrementally computed // string Name, Value; int i, k, count, index, length, offset, TotalResponseSize, TotalKnownHeadersLength = 0, TotalUnknownHeadersLength = 0, UnknownHeaderCount = 0; i = 0; count = m_WebHeaders.Count; for (k = 0; k < count; k++) { Name = (string)m_WebHeaders.GetKey(k); Value = (string)m_WebHeaders.Get(k); index = UL_HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(Name); if (index < 0) { // // unknown header // GlobalLog.Print(Name + " is unknown header Value:" + Value); UnknownHeaderCount++; TotalUnknownHeadersLength += Name.Length + Value.Length; } else { // // known header // GlobalLog.Print(Name + " is known header:" + Convert.ToString(index) + " Value:" + Value); TotalKnownHeadersLength += Value.Length; } } TotalResponseSize = 260 + // fixed size (includes know headers array) 2 * m_StatusDescription.Length + // staus description 2 * TotalKnownHeadersLength + // known headers 4 * 4 * UnknownHeaderCount + // unknow headers array 2 * TotalUnknownHeadersLength; // unknow headers // // allocate a managed UL_HTTP_RESPONSE structure, and store // unmanaged pinned memory pointers into structure members // IntPtr pResponse = Marshal.AllocHGlobal(TotalResponseSize); IntPtr pPointerOffset = ComNetOS.IsWinNt ? pResponse : IntPtr.Zero; GlobalLog.Print("Allocated " + Convert.ToString(TotalResponseSize) + " bytes from:" + Convert.ToString(pResponse) + " to fit Response"); Marshal.WriteInt16(pResponse, 0, 0); // Flags Marshal.WriteInt16(pResponse, 2, (short)m_Status); Marshal.WriteInt32(pResponse, 12, UnknownHeaderCount); offset = 260; length = 2 * m_StatusDescription.Length; Marshal.WriteInt32(pResponse, 4, length); Marshal.WriteInt32(pResponse, 8, pPointerOffset + offset); Marshal.Copy(Encoding.Unicode.GetBytes(m_StatusDescription), 0, pResponse + offset, length); offset += length; for (i = k = 0; i < 30; i++, k += 2) { Name = UL_HTTP_RESPONSE_HEADER_ID.ToString(i); Value = m_WebHeaders[Name]; Marshal.WriteInt64(pResponse, 20 + i * 8, 0); if (Value != null) { // // this known header key, has a value which is not null // length = 2 * Value.Length; Marshal.WriteInt16(pResponse, 20 + i * 8, (short)length); // could use 32 as well because of padding Marshal.WriteInt32(pResponse, 24 + i * 8, pPointerOffset + offset); Marshal.Copy(Encoding.Unicode.GetBytes(Value), 0, pResponse + offset, length); GlobalLog.Print("writing:" + Name + " from " + Convert.ToString(offset) + " to " + Convert.ToString(offset + length - 1)); offset += length; } } int pUnknownHeaders = offset; Marshal.WriteInt32(pResponse, 16, pPointerOffset + pUnknownHeaders); offset += UnknownHeaderCount * 16; i = 0; count = m_WebHeaders.Count; for (k = 0; k < count; k++) { Name = (string)m_WebHeaders.GetKey(k); Value = (string)m_WebHeaders.Get(k); index = UL_HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(Name); if (index < 0) { // // unknown header // GlobalLog.Print(Name + " is unknown header offset:" + Convert.ToString(offset)); length = 2 * Name.Length; Marshal.WriteInt32(pResponse, pUnknownHeaders + i * 16, length); Marshal.WriteInt32(pResponse, pUnknownHeaders + 4 + i * 16, pPointerOffset + offset); Marshal.Copy(Encoding.Unicode.GetBytes(Name), 0, pResponse + offset, length); GlobalLog.Print("writing:" + Name + " from " + Convert.ToString(offset) + " to " + Convert.ToString(offset + length - 1)); offset += length; length = 2 * Value.Length; Marshal.WriteInt32(pResponse, pUnknownHeaders + 8 + i * 16, length); Marshal.WriteInt32(pResponse, pUnknownHeaders + 12 + i * 16, pPointerOffset + offset); Marshal.Copy(Encoding.Unicode.GetBytes(Value), 0, pResponse + offset, length); GlobalLog.Print("writing:" + Value + " from " + Convert.ToString(offset) + " to " + Convert.ToString(offset + length - 1)); offset += length; i++; } } int DataWritten = 0; int result = ComNetOS.IsWinNt ? UlSysApi.UlSendHttpResponse( m_AppPoolHandle, m_RequestId, myFlags, pResponse, 0, IntPtr.Zero, IntPtr.Zero, ref DataWritten, IntPtr.Zero) : UlVxdApi.UlSendHttpResponseHeaders( m_AppPoolHandle, m_RequestId, 0, pResponse, // Response, TotalResponseSize, 0, IntPtr.Zero, IntPtr.Zero, ref DataWritten, IntPtr.Zero); GlobalLog.Print("UlSendHttpResponseHeaders() DataWritten: " + Convert.ToString(DataWritten)); Marshal.FreeHGlobal(pResponse); // // check return value, if IO is cancelled we'll throw // if (result != NativeMethods.ERROR_SUCCESS) { throw new IOException("Request/Response processing was cancelled"); } // // don't touch m_WebHeaders & m_StatusDescription anymore // m_ReadyToSendHeaders = false; // // if not create the Stream // m_ResponseStream = new ListenerResponseStream( m_AppPoolHandle, m_RequestId, m_ContentLength, m_SendChunked, m_KeepAlive); // // and return it to the user // return(m_ResponseStream); } // GetResponseStream()
m_InitializeUriListener() { if (ComNetOS.IsWinNt) { // // if this is WinNT we initialize ul.vxd // // // we need to create a special config group that allows for // transient registrations under the "http://*:80/" namespace // this will call UlInitialize() as well // int result = UlSysApi.UlCreateRootConfigGroup("http://*:80/"); if (result != 0) { throw new InvalidOperationException("Failed Initializing ul.sys"); } GlobalLog.Print("UlCreateRootConfigGroup() succeeded"); /* * // * // if we use this initialization we will need tcgsec.exe to be * // running in order to make this work * // * * int result = UlSysApi.UlInitialize(0); * * if ( result != 0 ) { * throw new InvalidOperationException( "Failed Initializing ul.sys" ); * } * * GlobalLog.Print("UL.SYS correctly initialized" ); */ } else if (ComNetOS.IsWin9x) { // // if this is Win9x we initialize ul.vxd // int result = UlVxdApi.UlInitialize(); if (result != 0) { throw new InvalidOperationException("Failed Initializing ul.vxd"); } GlobalLog.Print("UL.VXD correctly initialized"); } else { // // this is the only place in which we check for OperatingSystem other than // NT and Win9x, past this point we can assume that: // if it's not WinNt then it's Win9x. // throw new InvalidOperationException("Illegal OperatingSystem version"); } return(true); } // InitializeUriListener()
BeginGetRequest( AsyncCallback requestCallback, Object stateObject) { // // Validation // if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE) { throw new InvalidOperationException("The AppPool handle is invalid"); } // // prepare the ListenerAsyncResult object ( this will have it's own // event that the user can wait on for IO completion - which means we // need to signal it when IO completes ) // GlobalLog.Print("BeginGetRequest() creating ListenerAsyncResult"); ListenerAsyncResult AResult = new ListenerAsyncResult( stateObject, requestCallback); AutoResetEvent m_Event = new AutoResetEvent(false); Marshal.WriteIntPtr( AResult.m_Overlapped, Win32.OverlappedhEventOffset, m_Event.Handle); // // issue unmanaged call until we read enough data: // usually starting with a InitialBufferSize==4096 bytes we should be // able to get all the headers ( and part of the entity body, if any // is present ), if we don't, if the call didn't fail for othe reasons, // we get indication in BytesReturned, on how big the buffer should be // to receive the data available, so usually the second call will // succeed, but we have to consider the case of two competing calls // for the same RequestId, and that's why we need a loop and not just // a try/retry-expecting-success fashion // int result; for (;;) { // // check if we're in a healthy state // if (AResult.m_Retries++ > m_MaxRetries) { throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries"); } result = ComNetOS.IsWinNt ? UlSysApi.UlReceiveHttpRequest( m_AppPoolHandle, AResult.m_RequestId, UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY, AResult.m_Buffer, AResult.m_BufferSize, ref AResult.m_BytesReturned, AResult.m_Overlapped) : UlVxdApi.UlReceiveHttpRequestHeaders( m_AppPoolHandle, AResult.m_RequestId, 0, AResult.m_Buffer, AResult.m_BufferSize, ref AResult.m_BytesReturned, AResult.m_Overlapped); GlobalLog.Print("UlReceiveHttpRequest() returns:" + Convert.ToString(result)); if (result == NativeMethods.ERROR_SUCCESS || result == NativeMethods.ERROR_IO_PENDING) { // // synchronous success or successfull pending: we are done // break; } if (result == NativeMethods.ERROR_INVALID_PARAMETER) { // // we might get this if somebody stole our RequestId, // set RequestId to null // AResult.m_RequestId = 0; // // and start all over again with the buffer we // just allocated // continue; } if (result == NativeMethods.ERROR_MORE_DATA) { // // the buffer was not big enough to fit the headers, we need // to read the RequestId returned, grow the buffer, keeping // the data already transferred // AResult.m_RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AResult.m_Buffer, m_RequestIdOffset)); // // allocate a new buffer of the required size // IntPtr NewBuffer = Marshal.AllocHGlobal(AResult.m_BytesReturned); // // copy the data already read from the old buffer into the // new one // NativeMethods.CopyMemory(NewBuffer, AResult.m_Buffer, AResult.m_BufferSize); // // free the old buffer // Marshal.FreeHGlobal(AResult.m_Buffer); // // update buffer pointer and size // AResult.m_Buffer = NewBuffer; AResult.m_BufferSize = AResult.m_BytesReturned; AResult.m_BytesReturned = 0; // // and start all over again with the new buffer // continue; } // // someother bad error, possible( ? ) return values are: // // ERROR_INVALID_HANDLE // ERROR_INSUFFICIENT_BUFFER // ERROR_OPERATION_ABORTED // ERROR_IO_PENDING // throw new InvalidOperationException("UlReceiveHttpRequest() failed, err#" + Convert.ToString(result)); } // // we get here only if a break happens, i.e. // 1) syncronous completion // 2) the IO pended // if (result == NativeMethods.ERROR_SUCCESS) { // // set syncronous completion to true // AResult.Complete(true); // // and call the internal callback // WaitCallback(AResult, false); } else { // // create a new delegate // and spin a new thread from the thread pool to wake up when the // event is signaled and call the delegate // ThreadPool.RegisterWaitForSingleObject( m_Event, new WaitOrTimerCallback(WaitCallback), AResult, -1, true); } GlobalLog.Print("returning AResult"); return(AResult); } // StartListen()
GetRequest() { // // Validation // if (m_AppPoolHandle == NativeMethods.INVALID_HANDLE_VALUE) { throw new InvalidOperationException("The AppPool handle is invalid"); } int result; int retries = 0; // // defined in ulcommonapi.cs // int RcvHeadersBufferSize = UlConstants.InitialBufferSize; // // prepare ( allocate/pin ) buffers and data for the first unmanaged call // GCHandle PinnedBuffer; GCHandle NewPinnedBuffer; IntPtr AddrOfPinnedBuffer = IntPtr.Zero; IntPtr NewAddrOfPinnedBuffer = IntPtr.Zero; int BytesReturned = 0; long RequestId = 0; byte[] RcvHeadersBuffer = new byte[RcvHeadersBufferSize]; // // pin buffers and data for the unmanaged call // PinnedBuffer = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned); AddrOfPinnedBuffer = PinnedBuffer.AddrOfPinnedObject(); // // issue unmanaged blocking call until we read enough data: // usually starting with a InitialBufferSize==4096 bytes we should be // able to get all the headers ( and part of the entity body, if any // is present ), if we don't, if the call didn't fail for othe reasons, // we get indication in BytesReturned, on how big the buffer should be // to receive the data available, so usually the second call will // succeed, but we have to consider the case of two competing calls // for the same RequestId, and that's why we need a loop and not just // a try/retry-expecting-success fashion // for (;;) { // // check if we're in a healthy state // if (retries++ > m_MaxRetries) { throw new InvalidOperationException("UlReceiveHttpRequest() Too many retries"); } result = ComNetOS.IsWinNt ? UlSysApi.UlReceiveHttpRequest( m_AppPoolHandle, RequestId, UlConstants.UL_RECEIVE_REQUEST_FLAG_COPY_BODY, AddrOfPinnedBuffer, RcvHeadersBufferSize, ref BytesReturned, IntPtr.Zero) : UlVxdApi.UlReceiveHttpRequestHeaders( m_AppPoolHandle, RequestId, 0, AddrOfPinnedBuffer, RcvHeadersBufferSize, ref BytesReturned, IntPtr.Zero); if (result == NativeMethods.ERROR_SUCCESS) { // // success, we are done. // break; } if (result == NativeMethods.ERROR_INVALID_PARAMETER) { // // we might get this if somebody stole our RequestId, // set RequestId to null // RequestId = 0; // // and start all over again with the buffer we // just allocated // continue; } // // let's check if ul is in good shape: // if (BytesReturned < RcvHeadersBufferSize) { throw new InvalidOperationException("UlReceiveHttpRequest() sent bogus BytesReturned: " + Convert.ToString(BytesReturned)); } if (result == NativeMethods.ERROR_MORE_DATA) { // // the buffer was not big enough to fit the headers, we need // to read the RequestId returned, grow the buffer, keeping // the data already transferred // RequestId = Marshal.ReadInt64(IntPtrHelper.Add(AddrOfPinnedBuffer, m_RequestIdOffset)); // // CODEWORK: wait for the answer from LarrySu // // // if the buffer size was too small, grow the buffer // this reallocation dereferences the old buffer, but since // this was previously pinned, it won't be garbage collected // until we unpin it ( which we do below ) // RcvHeadersBuffer = new byte[BytesReturned]; // // pin the new one // NewPinnedBuffer = GCHandle.Alloc(RcvHeadersBuffer, GCHandleType.Pinned); NewAddrOfPinnedBuffer = NewPinnedBuffer.AddrOfPinnedObject(); // // copy the valid data // Marshal.Copy(AddrOfPinnedBuffer, RcvHeadersBuffer, 0, RcvHeadersBufferSize); RcvHeadersBufferSize = BytesReturned; // // unpin the old buffer, reset pinned/unmanaged pointers // PinnedBuffer.Free(); PinnedBuffer = NewPinnedBuffer; AddrOfPinnedBuffer = NewAddrOfPinnedBuffer; // // and start all over again with the new buffer // continue; } // // someother bad error, possible( ? ) return values are: // // ERROR_INVALID_HANDLE // ERROR_INSUFFICIENT_BUFFER // ERROR_OPERATION_ABORTED // ERROR_IO_PENDING // throw new InvalidOperationException("UlReceiveHttpRequest() failed, err#" + Convert.ToString(result)); } GlobalLog.Print("GetRequest RequestId:" + Convert.ToString(RequestId)); // // translate unmanaged results into a new managed object // HttpListenerWebRequest myWebRequest = new HttpListenerWebRequest(AddrOfPinnedBuffer, RcvHeadersBufferSize, m_AppPoolHandle); // // free the unmanaged buffer ( deallocate/unpin ) after unmanaged call // PinnedBuffer.Free(); return(myWebRequest); } // GetRequest()