diff --git a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp index 883e4ff49d510e957d8d7c7f7b8dc296d5b785c7..0328adec4ee351b4e40768ec5fa86abbbf82e686 100644 --- a/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp +++ b/src/Servers/IIS/AspNetCoreModuleV2/InProcessRequestHandler/inprocesshandler.cpp @@ -112,7 +112,7 @@ IN_PROCESS_HANDLER::NotifyDisconnect() if (pManagedHttpContext != nullptr) { - m_pDisconnectHandler(m_pManagedHttpContext); + m_pDisconnectHandler(pManagedHttpContext); } } @@ -139,14 +139,17 @@ IN_PROCESS_HANDLER::SetManagedHttpContext( PVOID pManagedHttpContext ) { + bool disconnectFired = false; + { SRWExclusiveLock lock(m_srwDisconnectLock); m_pManagedHttpContext = pManagedHttpContext; + disconnectFired = m_disconnectFired; } - if (m_disconnectFired && m_pManagedHttpContext != nullptr) + if (disconnectFired && pManagedHttpContext != nullptr) { - m_pDisconnectHandler(m_pManagedHttpContext); + m_pDisconnectHandler(pManagedHttpContext); } } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs index cae357e7761289b4882bffc76e4163005be3baee..3f7d3c53ce11cdd5df02aa5e0bad5bffc7731d52 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpContext.cs @@ -119,69 +119,75 @@ namespace Microsoft.AspNetCore.Server.IIS.Core protected void InitializeContext() { - _thisHandle = GCHandle.Alloc(this); + // create a memory barrier between initialize and disconnect to prevent a possible + // NullRef with disconnect being called before these fields have been written + // disconnect aquires this lock as well + lock (_abortLock) + { + _thisHandle = GCHandle.Alloc(this); - Method = GetVerb(); + Method = GetVerb(); - RawTarget = GetRawUrl(); - // TODO version is slow. - HttpVersion = GetVersion(); - Scheme = SslStatus != SslStatus.Insecure ? Constants.HttpsScheme : Constants.HttpScheme; - KnownMethod = VerbId; - StatusCode = 200; + RawTarget = GetRawUrl(); + // TODO version is slow. + HttpVersion = GetVersion(); + Scheme = SslStatus != SslStatus.Insecure ? Constants.HttpsScheme : Constants.HttpScheme; + KnownMethod = VerbId; + StatusCode = 200; - var originalPath = GetOriginalPath(); + var originalPath = GetOriginalPath(); - if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal)) - { - PathBase = string.Empty; - Path = string.Empty; - } - else - { - // Path and pathbase are unescaped by RequestUriBuilder - // The UsePathBase middleware will modify the pathbase and path correctly - PathBase = string.Empty; - Path = originalPath; - } + if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawTarget, "*", StringComparison.Ordinal)) + { + PathBase = string.Empty; + Path = string.Empty; + } + else + { + // Path and pathbase are unescaped by RequestUriBuilder + // The UsePathBase middleware will modify the pathbase and path correctly + PathBase = string.Empty; + Path = originalPath; + } - var cookedUrl = GetCookedUrl(); - QueryString = cookedUrl.GetQueryString() ?? string.Empty; + var cookedUrl = GetCookedUrl(); + QueryString = cookedUrl.GetQueryString() ?? string.Empty; - RequestHeaders = new RequestHeaders(this); - HttpResponseHeaders = new HeaderCollection(); - ResponseHeaders = HttpResponseHeaders; + RequestHeaders = new RequestHeaders(this); + HttpResponseHeaders = new HeaderCollection(); + ResponseHeaders = HttpResponseHeaders; - if (_options.ForwardWindowsAuthentication) - { - WindowsUser = GetWindowsPrincipal(); - if (_options.AutomaticAuthentication) + if (_options.ForwardWindowsAuthentication) { - User = WindowsUser; + WindowsUser = GetWindowsPrincipal(); + if (_options.AutomaticAuthentication) + { + User = WindowsUser; + } } - } - MaxRequestBodySize = _options.MaxRequestBodySize; + MaxRequestBodySize = _options.MaxRequestBodySize; - ResetFeatureCollection(); + ResetFeatureCollection(); - if (!_server.IsWebSocketAvailable(_pInProcessHandler)) - { - _currentIHttpUpgradeFeature = null; - } + if (!_server.IsWebSocketAvailable(_pInProcessHandler)) + { + _currentIHttpUpgradeFeature = null; + } - _streams = new Streams(this); + _streams = new Streams(this); - (RequestBody, ResponseBody) = _streams.Start(); + (RequestBody, ResponseBody) = _streams.Start(); - var pipe = new Pipe( - new PipeOptions( - _memoryPool, - readerScheduler: PipeScheduler.ThreadPool, - pauseWriterThreshold: PauseWriterThreshold, - resumeWriterThreshold: ResumeWriterTheshold, - minimumSegmentSize: MinAllocBufferSize)); - _bodyOutput = new OutputProducer(pipe); + var pipe = new Pipe( + new PipeOptions( + _memoryPool, + readerScheduler: PipeScheduler.ThreadPool, + pauseWriterThreshold: PauseWriterThreshold, + resumeWriterThreshold: ResumeWriterTheshold, + minimumSegmentSize: MinAllocBufferSize)); + _bodyOutput = new OutputProducer(pipe); + } NativeMethods.HttpSetManagedContext(_pInProcessHandler, (IntPtr)_thisHandle); } diff --git a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs index cb6c3db598e9b56de198e19d761c1494dc10d772..ef4c3aabb8f8f90c1c3b7d642e23a251571bf6b0 100644 --- a/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs +++ b/src/Servers/IIS/IIS/src/Core/IISHttpServer.cs @@ -170,7 +170,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core try { context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target; - context.AbortIO(clientDisconnect: true); + context?.AbortIO(clientDisconnect: true); } catch (Exception ex) { @@ -184,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.IIS.Core try { context = (IISHttpContext)GCHandle.FromIntPtr(pvManagedHttpContext).Target; - context.OnAsyncCompletion(hr, bytes); + context?.OnAsyncCompletion(hr, bytes); return NativeMethods.REQUEST_NOTIFICATION_STATUS.RQ_NOTIFICATION_PENDING; } catch (Exception ex)